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;
472 const gchar *account_id = NULL;
473 gboolean has_children;
475 rendobj = G_OBJECT(renderer);
476 gtk_tree_model_get (tree_model, iter,
477 TNY_GTK_FOLDER_STORE_TREE_MODEL_TYPE_COLUMN, &type,
478 TNY_GTK_FOLDER_STORE_TREE_MODEL_INSTANCE_COLUMN, &instance,
480 has_children = gtk_tree_model_iter_has_child (tree_model, iter);
485 /* MERGE is not needed anymore as the folder now has the correct type jschmid */
486 /* We include the MERGE type here because it's used to create
487 the local OUTBOX folder */
488 if (type == TNY_FOLDER_TYPE_NORMAL ||
489 type == TNY_FOLDER_TYPE_UNKNOWN) {
490 type = modest_tny_folder_guess_folder_type (TNY_FOLDER (instance));
494 case TNY_FOLDER_TYPE_ROOT:
495 if (TNY_IS_ACCOUNT (instance)) {
497 if (modest_tny_account_is_virtual_local_folders (
498 TNY_ACCOUNT (instance))) {
499 pixbuf = modest_platform_get_icon (MODEST_FOLDER_ICON_LOCAL_FOLDERS);
502 account_id = tny_account_get_id (TNY_ACCOUNT (instance));
504 if (!strcmp (account_id, MODEST_MMC_ACCOUNT_ID))
505 pixbuf = modest_platform_get_icon (MODEST_FOLDER_ICON_MMC);
507 pixbuf = modest_platform_get_icon (MODEST_FOLDER_ICON_ACCOUNT);
511 case TNY_FOLDER_TYPE_INBOX:
512 pixbuf = modest_platform_get_icon (MODEST_FOLDER_ICON_INBOX);
514 case TNY_FOLDER_TYPE_OUTBOX:
515 pixbuf = modest_platform_get_icon (MODEST_FOLDER_ICON_OUTBOX);
517 case TNY_FOLDER_TYPE_JUNK:
518 pixbuf = modest_platform_get_icon (MODEST_FOLDER_ICON_JUNK);
520 case TNY_FOLDER_TYPE_SENT:
521 pixbuf = modest_platform_get_icon (MODEST_FOLDER_ICON_SENT);
523 case TNY_FOLDER_TYPE_TRASH:
524 pixbuf = modest_platform_get_icon (MODEST_FOLDER_ICON_TRASH);
526 case TNY_FOLDER_TYPE_DRAFTS:
527 pixbuf = modest_platform_get_icon (MODEST_FOLDER_ICON_DRAFTS);
529 case TNY_FOLDER_TYPE_NORMAL:
531 pixbuf = modest_platform_get_icon (MODEST_FOLDER_ICON_NORMAL);
535 g_object_unref (G_OBJECT (instance));
538 g_object_set (rendobj, "pixbuf", pixbuf, NULL);
539 if (has_children && (pixbuf != NULL)) {
540 GdkPixbuf *open_pixbuf, *closed_pixbuf;
541 GdkPixbuf *open_emblem, *closed_emblem;
542 open_pixbuf = gdk_pixbuf_copy (pixbuf);
543 closed_pixbuf = gdk_pixbuf_copy (pixbuf);
544 open_emblem = modest_platform_get_icon ("qgn_list_gene_fldr_exp");
545 closed_emblem = modest_platform_get_icon ("qgn_list_gene_fldr_clp");
548 gdk_pixbuf_composite (open_emblem, open_pixbuf, 0, 0,
549 MIN (gdk_pixbuf_get_width (open_emblem),
550 gdk_pixbuf_get_width (open_pixbuf)),
551 MIN (gdk_pixbuf_get_height (open_emblem),
552 gdk_pixbuf_get_height (open_pixbuf)),
553 0, 0, 1, 1, GDK_INTERP_NEAREST, 255);
554 g_object_set (rendobj, "pixbuf-expander-open", open_pixbuf, NULL);
555 g_object_unref (open_emblem);
558 gdk_pixbuf_composite (closed_emblem, closed_pixbuf, 0, 0,
559 MIN (gdk_pixbuf_get_width (closed_emblem),
560 gdk_pixbuf_get_width (closed_pixbuf)),
561 MIN (gdk_pixbuf_get_height (closed_emblem),
562 gdk_pixbuf_get_height (closed_pixbuf)),
563 0, 0, 1, 1, GDK_INTERP_NEAREST, 255);
564 g_object_set (rendobj, "pixbuf-expander-closed", closed_pixbuf, NULL);
565 g_object_unref (closed_emblem);
568 g_object_unref (closed_pixbuf);
570 g_object_unref (open_pixbuf);
574 g_object_unref (pixbuf);
578 add_columns (GtkWidget *treeview)
580 GtkTreeViewColumn *column;
581 GtkCellRenderer *renderer;
582 GtkTreeSelection *sel;
585 column = gtk_tree_view_column_new ();
587 /* Set icon and text render function */
588 renderer = gtk_cell_renderer_pixbuf_new();
589 gtk_tree_view_column_pack_start (column, renderer, FALSE);
590 gtk_tree_view_column_set_cell_data_func(column, renderer,
591 icon_cell_data, treeview, NULL);
593 renderer = gtk_cell_renderer_text_new();
594 gtk_tree_view_column_pack_start (column, renderer, FALSE);
595 gtk_tree_view_column_set_cell_data_func(column, renderer,
596 text_cell_data, treeview, NULL);
598 /* Set selection mode */
599 sel = gtk_tree_view_get_selection (GTK_TREE_VIEW(treeview));
600 gtk_tree_selection_set_mode (sel, GTK_SELECTION_SINGLE);
602 /* Set treeview appearance */
603 gtk_tree_view_column_set_spacing (column, 2);
604 gtk_tree_view_column_set_resizable (column, TRUE);
605 gtk_tree_view_column_set_fixed_width (column, TRUE);
606 gtk_tree_view_set_headers_clickable (GTK_TREE_VIEW(treeview), FALSE);
607 gtk_tree_view_set_enable_search (GTK_TREE_VIEW(treeview), FALSE);
610 gtk_tree_view_append_column (GTK_TREE_VIEW(treeview),column);
614 modest_folder_view_init (ModestFolderView *obj)
616 ModestFolderViewPrivate *priv;
619 priv = MODEST_FOLDER_VIEW_GET_PRIVATE(obj);
621 priv->timer_expander = 0;
622 priv->account_store = NULL;
624 priv->style = MODEST_FOLDER_VIEW_STYLE_SHOW_ALL;
625 priv->cur_folder_store = NULL;
626 priv->visible_account_id = NULL;
627 priv->folder_to_select = NULL;
629 /* Initialize the local account name */
630 conf = modest_runtime_get_conf();
631 priv->local_account_name = modest_conf_get_string (conf, MODEST_CONF_DEVICE_NAME, NULL);
633 /* Init email clipboard */
634 priv->clipboard = modest_runtime_get_email_clipboard ();
635 priv->hidding_ids = NULL;
636 priv->n_selected = 0;
637 priv->reselect = FALSE;
638 priv->show_non_move = TRUE;
641 add_columns (GTK_WIDGET (obj));
643 /* Setup drag and drop */
644 setup_drag_and_drop (GTK_TREE_VIEW(obj));
646 /* Connect signals */
647 g_signal_connect (G_OBJECT (obj),
649 G_CALLBACK (on_key_pressed), NULL);
652 * Track changes in the local account name (in the device it
653 * will be the device name)
655 priv->conf_key_signal =
656 g_signal_connect (G_OBJECT(conf),
658 G_CALLBACK(on_configuration_key_changed), obj);
662 tny_account_store_view_init (gpointer g, gpointer iface_data)
664 TnyAccountStoreViewIface *klass = (TnyAccountStoreViewIface *)g;
666 klass->set_account_store_func = modest_folder_view_set_account_store;
672 modest_folder_view_finalize (GObject *obj)
674 ModestFolderViewPrivate *priv;
675 GtkTreeSelection *sel;
677 g_return_if_fail (obj);
679 priv = MODEST_FOLDER_VIEW_GET_PRIVATE(obj);
681 if (priv->timer_expander != 0) {
682 g_source_remove (priv->timer_expander);
683 priv->timer_expander = 0;
686 if (priv->account_store) {
687 g_signal_handler_disconnect (G_OBJECT(priv->account_store),
688 priv->account_update_signal);
689 g_signal_handler_disconnect (G_OBJECT(priv->account_store),
690 priv->accounts_reloaded_signal);
691 g_signal_handler_disconnect (G_OBJECT(priv->account_store),
692 priv->account_removed_signal);
693 g_object_unref (G_OBJECT(priv->account_store));
694 priv->account_store = NULL;
698 g_object_unref (G_OBJECT (priv->query));
702 if (priv->folder_to_select) {
703 g_object_unref (G_OBJECT(priv->folder_to_select));
704 priv->folder_to_select = NULL;
707 sel = gtk_tree_view_get_selection (GTK_TREE_VIEW(obj));
709 g_signal_handler_disconnect (G_OBJECT(sel), priv->changed_signal);
711 g_free (priv->local_account_name);
712 g_free (priv->visible_account_id);
714 if (priv->conf_key_signal) {
715 g_signal_handler_disconnect (modest_runtime_get_conf (),
716 priv->conf_key_signal);
717 priv->conf_key_signal = 0;
720 if (priv->cur_folder_store) {
721 if (TNY_IS_FOLDER(priv->cur_folder_store))
722 tny_folder_sync (TNY_FOLDER(priv->cur_folder_store), FALSE, NULL);
723 /* FALSE --> expunge the message */
725 g_object_unref (priv->cur_folder_store);
726 priv->cur_folder_store = NULL;
729 /* Clear hidding array created by cut operation */
730 _clear_hidding_filter (MODEST_FOLDER_VIEW (obj));
732 G_OBJECT_CLASS(parent_class)->finalize (obj);
737 modest_folder_view_set_account_store (TnyAccountStoreView *self, TnyAccountStore *account_store)
739 ModestFolderViewPrivate *priv;
742 g_return_if_fail (MODEST_IS_FOLDER_VIEW (self));
743 g_return_if_fail (TNY_IS_ACCOUNT_STORE (account_store));
745 priv = MODEST_FOLDER_VIEW_GET_PRIVATE (self);
746 device = tny_account_store_get_device (account_store);
748 if (G_UNLIKELY (priv->account_store)) {
750 if (g_signal_handler_is_connected (G_OBJECT (priv->account_store),
751 priv->account_update_signal))
752 g_signal_handler_disconnect (G_OBJECT (priv->account_store),
753 priv->account_update_signal);
754 if (g_signal_handler_is_connected (G_OBJECT (priv->account_store),
755 priv->accounts_reloaded_signal))
756 g_signal_handler_disconnect (G_OBJECT (priv->account_store),
757 priv->accounts_reloaded_signal);
758 if (g_signal_handler_is_connected (G_OBJECT (priv->account_store),
759 priv->account_removed_signal))
760 g_signal_handler_disconnect (G_OBJECT (priv->account_store),
761 priv->account_removed_signal);
763 g_object_unref (G_OBJECT (priv->account_store));
766 priv->account_store = g_object_ref (G_OBJECT (account_store));
768 priv->account_update_signal =
769 g_signal_connect (G_OBJECT(account_store), "account_update",
770 G_CALLBACK (on_account_update), self);
772 priv->account_removed_signal =
773 g_signal_connect (G_OBJECT(account_store), "account_removed",
774 G_CALLBACK (on_account_removed), self);
776 priv->accounts_reloaded_signal =
777 g_signal_connect (G_OBJECT(account_store), "accounts_reloaded",
778 G_CALLBACK (on_accounts_reloaded), self);
780 g_signal_connect (G_OBJECT(account_store), "connecting_finished",
781 G_CALLBACK (on_accounts_reloaded), self);
783 on_accounts_reloaded (account_store, (gpointer ) self);
785 g_object_unref (G_OBJECT (device));
789 on_account_removed (TnyAccountStore *account_store,
793 ModestFolderView *self = MODEST_FOLDER_VIEW (user_data);
794 ModestFolderViewPrivate *priv;
796 priv = MODEST_FOLDER_VIEW_GET_PRIVATE (self);
798 /* If the removed account is the currently viewed one then
799 clear the configuration value. The new visible account will be the default account */
800 if (priv->visible_account_id &&
801 !strcmp (priv->visible_account_id, tny_account_get_id (account))) {
803 /* Clear the current visible account_id */
804 modest_folder_view_set_account_id_of_visible_server_account (self, NULL);
806 /* Call the restore method, this will set the new visible account */
807 modest_widget_memory_restore (modest_runtime_get_conf(), G_OBJECT(self),
808 MODEST_CONF_FOLDER_VIEW_KEY);
810 /* Select the INBOX */
811 modest_folder_view_select_first_inbox_or_local (self);
816 on_account_update (TnyAccountStore *account_store,
817 const gchar *account,
820 ModestFolderView *self = NULL;
821 ModestFolderViewPrivate *priv;
823 g_return_if_fail (MODEST_IS_FOLDER_VIEW (user_data));
824 self = MODEST_FOLDER_VIEW (user_data);
825 priv = MODEST_FOLDER_VIEW_GET_PRIVATE (self);
827 /* If we're adding a new account, and there is no previous
828 one, we need to select the visible server account */
829 if (priv->style == MODEST_FOLDER_VIEW_STYLE_SHOW_ONE &&
830 !priv->visible_account_id)
831 modest_widget_memory_restore (modest_runtime_get_conf(), G_OBJECT(self),
832 MODEST_CONF_FOLDER_VIEW_KEY);
834 if (!modest_folder_view_update_model (self, account_store))
835 g_printerr ("modest: failed to update model for changes in '%s'",
840 on_accounts_reloaded (TnyAccountStore *account_store,
843 g_return_if_fail (MODEST_IS_FOLDER_VIEW (user_data));
844 modest_folder_view_update_model (MODEST_FOLDER_VIEW (user_data), account_store);
848 modest_folder_view_set_title (ModestFolderView *self, const gchar *title)
850 GtkTreeViewColumn *col;
852 g_return_if_fail (self);
854 col = gtk_tree_view_get_column (GTK_TREE_VIEW(self), 0);
856 g_printerr ("modest: failed get column for title\n");
860 gtk_tree_view_column_set_title (col, title);
861 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW(self),
866 modest_folder_view_on_map (ModestFolderView *self,
867 GdkEventExpose *event,
870 ModestFolderViewPrivate *priv;
872 priv = MODEST_FOLDER_VIEW_GET_PRIVATE (self);
874 /* This won't happen often */
875 if (G_UNLIKELY (priv->reselect)) {
876 /* Select the first inbox or the local account if not found */
878 /* TODO: this could cause a lock at startup, so we
879 comment it for the moment. We know that this will
880 be a bug, because the INBOX is not selected, but we
881 need to rewrite some parts of Modest to avoid the
882 deathlock situation */
883 /* TODO: check if this is still the case */
884 priv->reselect = FALSE;
885 modest_folder_view_select_first_inbox_or_local (self);
886 /* Notify the display name observers */
887 g_signal_emit (G_OBJECT(self),
888 signals[FOLDER_DISPLAY_NAME_CHANGED_SIGNAL], 0,
895 modest_folder_view_new (TnyFolderStoreQuery *query)
898 ModestFolderViewPrivate *priv;
899 GtkTreeSelection *sel;
901 self = G_OBJECT (g_object_new (MODEST_TYPE_FOLDER_VIEW, NULL));
902 priv = MODEST_FOLDER_VIEW_GET_PRIVATE (self);
905 priv->query = g_object_ref (query);
907 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(self));
908 priv->changed_signal = g_signal_connect (sel, "changed",
909 G_CALLBACK (on_selection_changed), self);
911 g_signal_connect (self, "expose-event", G_CALLBACK (modest_folder_view_on_map), NULL);
913 return GTK_WIDGET(self);
916 /* this feels dirty; any other way to expand all the root items? */
918 expand_root_items (ModestFolderView *self)
921 path = gtk_tree_path_new_first ();
923 /* all folders should have child items, so.. */
924 while (gtk_tree_view_expand_row (GTK_TREE_VIEW(self), path, FALSE))
925 gtk_tree_path_next (path);
927 gtk_tree_path_free (path);
931 * We use this function to implement the
932 * MODEST_FOLDER_VIEW_STYLE_SHOW_ONE style. We only show the default
933 * account in this case, and the local folders.
936 filter_row (GtkTreeModel *model,
940 ModestFolderViewPrivate *priv;
941 gboolean retval = TRUE;
942 TnyFolderType type = TNY_FOLDER_TYPE_UNKNOWN;
943 GObject *instance = NULL;
944 const gchar *id = NULL;
946 gboolean found = FALSE;
947 gboolean cleared = FALSE;
949 g_return_val_if_fail (MODEST_IS_FOLDER_VIEW (data), FALSE);
950 priv = MODEST_FOLDER_VIEW_GET_PRIVATE (data);
952 gtk_tree_model_get (model, iter,
953 TNY_GTK_FOLDER_STORE_TREE_MODEL_TYPE_COLUMN, &type,
954 TNY_GTK_FOLDER_STORE_TREE_MODEL_INSTANCE_COLUMN, &instance,
957 /* Do not show if there is no instance, this could indeed
958 happen when the model is being modified while it's being
959 drawn. This could occur for example when moving folders
964 if (type == TNY_FOLDER_TYPE_ROOT) {
965 /* TNY_FOLDER_TYPE_ROOT means that the instance is an
966 account instead of a folder. */
967 if (TNY_IS_ACCOUNT (instance)) {
968 TnyAccount *acc = TNY_ACCOUNT (instance);
969 const gchar *account_id = tny_account_get_id (acc);
971 /* If it isn't a special folder,
972 * don't show it unless it is the visible account: */
973 if (priv->style == MODEST_FOLDER_VIEW_STYLE_SHOW_ONE &&
974 !modest_tny_account_is_virtual_local_folders (acc) &&
975 strcmp (account_id, MODEST_MMC_ACCOUNT_ID)) {
977 /* Show only the visible account id */
978 if (priv->visible_account_id) {
979 if (strcmp (account_id, priv->visible_account_id))
986 /* Never show these to the user. They are merged into one folder
987 * in the local-folders account instead: */
988 if (retval && MODEST_IS_TNY_OUTBOX_ACCOUNT (acc))
993 /* Check hiding (if necessary) */
994 cleared = modest_email_clipboard_cleared (priv->clipboard);
995 if ((retval) && (!cleared) && (TNY_IS_FOLDER (instance))) {
996 id = tny_folder_get_id (TNY_FOLDER(instance));
997 if (priv->hidding_ids != NULL)
998 for (i=0; i < priv->n_selected && !found; i++)
999 if (priv->hidding_ids[i] != NULL && id != NULL)
1000 found = (!strcmp (priv->hidding_ids[i], id));
1006 /* If this is a move to dialog, hide Sent, Outbox and Drafts
1007 folder as no message can be move there according to UI specs */
1008 if (!priv->show_non_move)
1012 case TNY_FOLDER_TYPE_OUTBOX:
1013 case TNY_FOLDER_TYPE_SENT:
1014 case TNY_FOLDER_TYPE_DRAFTS:
1017 case TNY_FOLDER_TYPE_UNKNOWN:
1018 case TNY_FOLDER_TYPE_NORMAL:
1019 type = modest_tny_folder_guess_folder_type(TNY_FOLDER(instance));
1020 if (type == TNY_FOLDER_TYPE_OUTBOX || type == TNY_FOLDER_TYPE_SENT
1021 || type == TNY_FOLDER_TYPE_DRAFTS)
1032 g_object_unref (instance);
1039 modest_folder_view_update_model (ModestFolderView *self,
1040 TnyAccountStore *account_store)
1042 ModestFolderViewPrivate *priv;
1043 GtkTreeModel *model /* , *old_model */;
1044 /* TnyAccount *local_account; */
1045 TnyList *model_as_list;
1047 g_return_val_if_fail (MODEST_IS_FOLDER_VIEW (self), FALSE);
1048 g_return_val_if_fail (account_store, FALSE);
1050 priv = MODEST_FOLDER_VIEW_GET_PRIVATE(self);
1052 /* Notify that there is no folder selected */
1053 g_signal_emit (G_OBJECT(self),
1054 signals[FOLDER_SELECTION_CHANGED_SIGNAL], 0,
1056 if (priv->cur_folder_store) {
1057 g_object_unref (priv->cur_folder_store);
1058 priv->cur_folder_store = NULL;
1061 /* FIXME: the local accounts are not shown when the query
1062 selects only the subscribed folders. */
1063 /* model = tny_gtk_folder_store_tree_model_new (TRUE, priv->query); */
1064 model = tny_gtk_folder_store_tree_model_new (TRUE, NULL);
1066 /* Deal with the model via its TnyList Interface,
1067 * filling the TnyList via a get_accounts() call: */
1068 model_as_list = TNY_LIST(model);
1070 /* Get the accounts: */
1071 tny_account_store_get_accounts (TNY_ACCOUNT_STORE(account_store),
1073 TNY_ACCOUNT_STORE_STORE_ACCOUNTS);
1074 g_object_unref (model_as_list);
1075 model_as_list = NULL;
1077 GtkTreeModel *filter_model = NULL, *sortable = NULL;
1079 sortable = gtk_tree_model_sort_new_with_model (model);
1080 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE(sortable),
1081 TNY_GTK_FOLDER_STORE_TREE_MODEL_NAME_COLUMN,
1082 GTK_SORT_ASCENDING);
1083 gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (sortable),
1084 TNY_GTK_FOLDER_STORE_TREE_MODEL_NAME_COLUMN,
1085 cmp_rows, NULL, NULL);
1087 /* Create filter model */
1088 filter_model = gtk_tree_model_filter_new (sortable, NULL);
1089 gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter_model),
1095 gtk_tree_view_set_model (GTK_TREE_VIEW(self), filter_model);
1096 g_signal_connect (G_OBJECT(filter_model), "row-changed",
1097 (GCallback)on_row_changed_maybe_select_folder, self);
1098 g_signal_connect (G_OBJECT(filter_model), "row-inserted",
1099 (GCallback)on_row_changed_maybe_select_folder, self);
1102 g_object_unref (model);
1103 g_object_unref (filter_model);
1104 g_object_unref (sortable);
1106 /* Force a reselection of the INBOX next time the widget is shown */
1107 priv->reselect = TRUE;
1114 on_selection_changed (GtkTreeSelection *sel, gpointer user_data)
1116 GtkTreeModel *model;
1117 TnyFolderStore *folder = NULL;
1119 ModestFolderView *tree_view;
1120 ModestFolderViewPrivate *priv;
1122 g_return_if_fail (sel);
1123 g_return_if_fail (user_data);
1125 priv = MODEST_FOLDER_VIEW_GET_PRIVATE(user_data);
1127 if(!gtk_tree_selection_get_selected (sel, &model, &iter))
1130 /* Notify the display name observers */
1131 g_signal_emit (G_OBJECT(user_data),
1132 signals[FOLDER_DISPLAY_NAME_CHANGED_SIGNAL], 0,
1135 tree_view = MODEST_FOLDER_VIEW (user_data);
1136 gtk_tree_model_get (model, &iter,
1137 TNY_GTK_FOLDER_STORE_TREE_MODEL_INSTANCE_COLUMN, &folder,
1140 /* If the folder is the same do not notify */
1141 if (priv->cur_folder_store == folder && folder) {
1142 g_object_unref (folder);
1146 /* Current folder was unselected */
1147 if (priv->cur_folder_store) {
1148 g_signal_emit (G_OBJECT(tree_view), signals[FOLDER_SELECTION_CHANGED_SIGNAL], 0,
1149 priv->cur_folder_store, FALSE);
1151 if (TNY_IS_FOLDER(priv->cur_folder_store))
1152 tny_folder_sync_async (TNY_FOLDER(priv->cur_folder_store),
1153 FALSE, NULL, NULL, NULL);
1154 /* FALSE --> don't expunge the messages */
1156 g_object_unref (priv->cur_folder_store);
1157 priv->cur_folder_store = NULL;
1160 /* New current references */
1161 priv->cur_folder_store = folder;
1163 /* New folder has been selected */
1164 g_signal_emit (G_OBJECT(tree_view),
1165 signals[FOLDER_SELECTION_CHANGED_SIGNAL],
1166 0, priv->cur_folder_store, TRUE);
1170 modest_folder_view_get_selected (ModestFolderView *self)
1172 ModestFolderViewPrivate *priv;
1174 g_return_val_if_fail (self, NULL);
1176 priv = MODEST_FOLDER_VIEW_GET_PRIVATE(self);
1177 if (priv->cur_folder_store)
1178 g_object_ref (priv->cur_folder_store);
1180 return priv->cur_folder_store;
1184 get_cmp_rows_type_pos (GObject *folder)
1186 /* Remote accounts -> Local account -> MMC account .*/
1189 if (TNY_IS_ACCOUNT (folder) &&
1190 modest_tny_account_is_virtual_local_folders (
1191 TNY_ACCOUNT (folder))) {
1193 } else if (TNY_IS_ACCOUNT (folder)) {
1194 TnyAccount *account = TNY_ACCOUNT (folder);
1195 const gchar *account_id = tny_account_get_id (account);
1196 if (!strcmp (account_id, MODEST_MMC_ACCOUNT_ID))
1202 printf ("DEBUG: %s: unexpected type.\n", __FUNCTION__);
1203 return -1; /* Should never happen */
1208 get_cmp_subfolder_type_pos (TnyFolderType t)
1210 /* Inbox, Outbox, Drafts, Sent, User */
1214 case TNY_FOLDER_TYPE_INBOX:
1217 case TNY_FOLDER_TYPE_OUTBOX:
1220 case TNY_FOLDER_TYPE_DRAFTS:
1223 case TNY_FOLDER_TYPE_SENT:
1232 * This function orders the mail accounts according to these rules:
1233 * 1st - remote accounts
1234 * 2nd - local account
1238 cmp_rows (GtkTreeModel *tree_model, GtkTreeIter *iter1, GtkTreeIter *iter2,
1242 gchar *name1 = NULL;
1243 gchar *name2 = NULL;
1244 TnyFolderType type = TNY_FOLDER_TYPE_UNKNOWN;
1245 TnyFolderType type2 = TNY_FOLDER_TYPE_UNKNOWN;
1246 GObject *folder1 = NULL;
1247 GObject *folder2 = NULL;
1249 gtk_tree_model_get (tree_model, iter1,
1250 TNY_GTK_FOLDER_STORE_TREE_MODEL_NAME_COLUMN, &name1,
1251 TNY_GTK_FOLDER_STORE_TREE_MODEL_TYPE_COLUMN, &type,
1252 TNY_GTK_FOLDER_STORE_TREE_MODEL_INSTANCE_COLUMN, &folder1,
1254 gtk_tree_model_get (tree_model, iter2,
1255 TNY_GTK_FOLDER_STORE_TREE_MODEL_NAME_COLUMN, &name2,
1256 TNY_GTK_FOLDER_STORE_TREE_MODEL_TYPE_COLUMN, &type2,
1257 TNY_GTK_FOLDER_STORE_TREE_MODEL_INSTANCE_COLUMN, &folder2,
1260 /* Return if we get no folder. This could happen when folder
1261 operations are happening. The model is updated after the
1262 folder copy/move actually occurs, so there could be
1263 situations where the model to be drawn is not correct */
1264 if (!folder1 || !folder2)
1267 if (type == TNY_FOLDER_TYPE_ROOT) {
1268 /* Compare the types, so that
1269 * Remote accounts -> Local account -> MMC account .*/
1270 const gint pos1 = get_cmp_rows_type_pos (folder1);
1271 const gint pos2 = get_cmp_rows_type_pos (folder2);
1272 /* printf ("DEBUG: %s:\n type1=%s, pos1=%d\n type2=%s, pos2=%d\n",
1273 __FUNCTION__, G_OBJECT_TYPE_NAME(folder1), pos1, G_OBJECT_TYPE_NAME(folder2), pos2); */
1276 else if (pos1 > pos2)
1279 /* Compare items of the same type: */
1281 TnyAccount *account1 = NULL;
1282 if (TNY_IS_ACCOUNT (folder1))
1283 account1 = TNY_ACCOUNT (folder1);
1285 TnyAccount *account2 = NULL;
1286 if (TNY_IS_ACCOUNT (folder2))
1287 account2 = TNY_ACCOUNT (folder2);
1289 const gchar *account_id = account1 ? tny_account_get_id (account1) : NULL;
1290 const gchar *account_id2 = account2 ? tny_account_get_id (account2) : NULL;
1292 if (!account_id && !account_id2) {
1294 } else if (!account_id) {
1296 } else if (!account_id2) {
1298 } else if (!strcmp (account_id, MODEST_MMC_ACCOUNT_ID)) {
1301 cmp = modest_text_utils_utf8_strcmp (name1, name2, TRUE);
1305 gint cmp1 = 0, cmp2 = 0;
1306 /* get the parent to know if it's a local folder */
1309 gboolean has_parent;
1310 has_parent = gtk_tree_model_iter_parent (tree_model, &parent, iter1);
1312 GObject *parent_folder;
1313 TnyFolderType parent_type = TNY_FOLDER_TYPE_UNKNOWN;
1314 gtk_tree_model_get (tree_model, &parent,
1315 TNY_GTK_FOLDER_STORE_TREE_MODEL_TYPE_COLUMN, &parent_type,
1316 TNY_GTK_FOLDER_STORE_TREE_MODEL_INSTANCE_COLUMN, &parent_folder,
1318 if ((parent_type == TNY_FOLDER_TYPE_ROOT) &&
1319 TNY_IS_ACCOUNT (parent_folder) &&
1320 modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (parent_folder))) {
1321 cmp1 = get_cmp_subfolder_type_pos (modest_tny_folder_get_local_or_mmc_folder_type (TNY_FOLDER (folder1)));
1322 cmp2 = get_cmp_subfolder_type_pos (modest_tny_folder_get_local_or_mmc_folder_type (TNY_FOLDER (folder2)));
1324 g_object_unref (parent_folder);
1327 /* if they are not local folders */
1329 cmp1 = get_cmp_subfolder_type_pos (tny_folder_get_folder_type (TNY_FOLDER (folder1)));
1330 cmp2 = get_cmp_subfolder_type_pos (tny_folder_get_folder_type (TNY_FOLDER (folder2)));
1334 cmp = modest_text_utils_utf8_strcmp (name1, name2, TRUE);
1336 cmp = (cmp1 - cmp2);
1341 g_object_unref(G_OBJECT(folder1));
1343 g_object_unref(G_OBJECT(folder2));
1351 /*****************************************************************************/
1352 /* DRAG and DROP stuff */
1353 /*****************************************************************************/
1356 * This function fills the #GtkSelectionData with the row and the
1357 * model that has been dragged. It's called when this widget is a
1358 * source for dnd after the event drop happened
1361 on_drag_data_get (GtkWidget *widget,
1362 GdkDragContext *context,
1363 GtkSelectionData *selection_data,
1368 GtkTreeSelection *selection;
1369 GtkTreeModel *model;
1371 GtkTreePath *source_row;
1373 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget));
1374 gtk_tree_selection_get_selected (selection, &model, &iter);
1375 source_row = gtk_tree_model_get_path (model, &iter);
1377 gtk_tree_set_row_drag_data (selection_data,
1381 gtk_tree_path_free (source_row);
1384 typedef struct _DndHelper {
1385 gboolean delete_source;
1386 GtkTreePath *source_row;
1387 GdkDragContext *context;
1393 * This function is the callback of the
1394 * modest_mail_operation_xfer_msgs () and
1395 * modest_mail_operation_xfer_folder() calls. We check here if the
1396 * message/folder was correctly asynchronously transferred. The reason
1397 * to use the same callback is that the code is the same, it only has
1398 * to check that the operation went fine and then finalize the drag
1402 on_progress_changed (ModestMailOperation *mail_op,
1403 ModestMailOperationState *state,
1409 helper = (DndHelper *) user_data;
1411 if (!state->finished)
1414 if (state->status == MODEST_MAIL_OPERATION_STATUS_SUCCESS) {
1420 /* Notify the drag source. Never call delete, the monitor will
1421 do the job if needed */
1422 gtk_drag_finish (helper->context, success, FALSE, helper->time);
1424 /* Free the helper */
1425 gtk_tree_path_free (helper->source_row);
1426 g_slice_free (DndHelper, helper);
1430 /* get the folder for the row the treepath refers to. */
1431 /* folder must be unref'd */
1433 tree_path_to_folder (GtkTreeModel *model, GtkTreePath *path)
1436 TnyFolder *folder = NULL;
1438 if (gtk_tree_model_get_iter (model,&iter, path))
1439 gtk_tree_model_get (model, &iter,
1440 TNY_GTK_FOLDER_STORE_TREE_MODEL_INSTANCE_COLUMN, &folder,
1446 * This function is used by drag_data_received_cb to manage drag and
1447 * drop of a header, i.e, and drag from the header view to the folder
1451 drag_and_drop_from_header_view (GtkTreeModel *source_model,
1452 GtkTreeModel *dest_model,
1453 GtkTreePath *dest_row,
1456 TnyList *headers = NULL;
1457 TnyHeader *header = NULL;
1458 TnyFolder *folder = NULL;
1459 ModestMailOperation *mail_op = NULL;
1460 GtkTreeIter source_iter;
1462 g_return_if_fail (GTK_IS_TREE_MODEL(source_model));
1463 g_return_if_fail (GTK_IS_TREE_MODEL(dest_model));
1464 g_return_if_fail (dest_row);
1465 g_return_if_fail (helper);
1468 gtk_tree_model_get_iter (source_model, &source_iter, helper->source_row);
1469 gtk_tree_model_get (source_model, &source_iter,
1470 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1472 if (!TNY_IS_HEADER(header)) {
1473 g_warning ("BUG: %s could not get a valid header", __FUNCTION__);
1478 folder = tree_path_to_folder (dest_model, dest_row);
1479 if (!TNY_IS_FOLDER(folder)) {
1480 g_warning ("BUG: %s could not get a valid folder", __FUNCTION__);
1483 if (modest_tny_folder_get_rules(folder) & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1484 g_debug ("folder rules: cannot write to that folder");
1489 /* Transfer message */
1490 mail_op = modest_mail_operation_new_with_error_handling (MODEST_MAIL_OPERATION_TYPE_RECEIVE,
1492 modest_ui_actions_move_folder_error_handler,
1494 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (),
1496 g_signal_connect (G_OBJECT (mail_op), "progress-changed",
1497 G_CALLBACK (on_progress_changed), helper);
1499 headers = tny_simple_list_new ();
1500 tny_list_append (headers, G_OBJECT (header));
1501 modest_mail_operation_xfer_msgs (mail_op,
1504 helper->delete_source,
1509 if (G_IS_OBJECT(mail_op))
1510 g_object_unref (G_OBJECT (mail_op));
1511 if (G_IS_OBJECT(header))
1512 g_object_unref (G_OBJECT (header));
1513 if (G_IS_OBJECT(folder))
1514 g_object_unref (G_OBJECT (folder));
1515 if (G_IS_OBJECT(headers))
1516 g_object_unref (headers);
1520 * This function is used by drag_data_received_cb to manage drag and
1521 * drop of a folder, i.e, and drag from the folder view to the same
1525 drag_and_drop_from_folder_view (GtkTreeModel *source_model,
1526 GtkTreeModel *dest_model,
1527 GtkTreePath *dest_row,
1528 GtkSelectionData *selection_data,
1531 ModestMailOperation *mail_op = NULL;
1532 GtkTreeIter parent_iter, iter;
1533 TnyFolderStore *parent_folder = NULL;
1534 TnyFolder *folder = NULL;
1535 gboolean forbidden = TRUE;
1537 /* check the folder rules for the destination */
1538 folder = tree_path_to_folder (dest_model, dest_row);
1540 ModestTnyFolderRules rules =
1541 modest_tny_folder_get_rules (folder);
1542 forbidden = rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE;
1544 g_debug ("folder rules: cannot write to that folder");
1545 g_object_unref (folder);
1549 /* check the folder rules for the source */
1550 folder = tree_path_to_folder (source_model, helper->source_row);
1552 ModestTnyFolderRules rules =
1553 modest_tny_folder_get_rules (folder);
1554 forbidden = rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE;
1556 g_debug ("folder rules: cannot move that folder");
1557 g_object_unref (folder);
1562 /* Check if the drag is possible */
1563 if (forbidden || !gtk_tree_path_compare (helper->source_row, dest_row)) {
1565 gtk_drag_finish (helper->context, FALSE, FALSE, helper->time);
1566 gtk_tree_path_free (helper->source_row);
1567 g_slice_free (DndHelper, helper);
1572 gtk_tree_model_get_iter (source_model, &parent_iter, dest_row);
1573 gtk_tree_model_get_iter (source_model, &iter, helper->source_row);
1574 gtk_tree_model_get (source_model, &parent_iter,
1575 TNY_GTK_FOLDER_STORE_TREE_MODEL_INSTANCE_COLUMN,
1576 &parent_folder, -1);
1577 gtk_tree_model_get (source_model, &iter,
1578 TNY_GTK_FOLDER_STORE_TREE_MODEL_INSTANCE_COLUMN,
1581 /* Offer the connection dialog if necessary, for the destination parent folder and source folder: */
1582 if (modest_platform_connect_and_wait_if_network_folderstore (NULL, parent_folder) &&
1583 modest_platform_connect_and_wait_if_network_folderstore (NULL, TNY_FOLDER_STORE (folder))) {
1584 /* Do the mail operation */
1585 mail_op = modest_mail_operation_new_with_error_handling (MODEST_MAIL_OPERATION_TYPE_RECEIVE,
1587 modest_ui_actions_move_folder_error_handler,
1589 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (),
1591 g_signal_connect (G_OBJECT (mail_op), "progress-changed",
1592 G_CALLBACK (on_progress_changed), helper);
1594 modest_mail_operation_xfer_folder (mail_op,
1597 helper->delete_source,
1601 g_object_unref (G_OBJECT (mail_op));
1605 g_object_unref (G_OBJECT (parent_folder));
1606 g_object_unref (G_OBJECT (folder));
1610 * This function receives the data set by the "drag-data-get" signal
1611 * handler. This information comes within the #GtkSelectionData. This
1612 * function will manage both the drags of folders of the treeview and
1613 * drags of headers of the header view widget.
1616 on_drag_data_received (GtkWidget *widget,
1617 GdkDragContext *context,
1620 GtkSelectionData *selection_data,
1625 GtkWidget *source_widget;
1626 GtkTreeModel *dest_model, *source_model;
1627 GtkTreePath *source_row, *dest_row;
1628 GtkTreeViewDropPosition pos;
1629 gboolean success = FALSE, delete_source = FALSE;
1630 DndHelper *helper = NULL;
1632 /* Do not allow further process */
1633 g_signal_stop_emission_by_name (widget, "drag-data-received");
1634 source_widget = gtk_drag_get_source_widget (context);
1636 /* Get the action */
1637 if (context->action == GDK_ACTION_MOVE) {
1638 delete_source = TRUE;
1640 /* Notify that there is no folder selected. We need to
1641 do this in order to update the headers view (and
1642 its monitors, because when moving, the old folder
1643 won't longer exist. We can not wait for the end of
1644 the operation, because the operation won't start if
1645 the folder is in use */
1646 if (source_widget == widget) {
1647 ModestFolderViewPrivate *priv;
1649 priv = MODEST_FOLDER_VIEW_GET_PRIVATE (widget);
1650 if (priv->cur_folder_store) {
1651 g_object_unref (priv->cur_folder_store);
1652 priv->cur_folder_store = NULL;
1655 g_signal_emit (G_OBJECT (widget),
1656 signals[FOLDER_SELECTION_CHANGED_SIGNAL], 0, NULL, FALSE);
1660 /* Check if the get_data failed */
1661 if (selection_data == NULL || selection_data->length < 0)
1662 gtk_drag_finish (context, success, FALSE, time);
1664 /* Get the models */
1665 gtk_tree_get_row_drag_data (selection_data,
1669 /* Select the destination model */
1670 if (source_widget == widget) {
1671 dest_model = source_model;
1673 dest_model = gtk_tree_view_get_model (GTK_TREE_VIEW (widget));
1676 /* Get the path to the destination row. Can not call
1677 gtk_tree_view_get_drag_dest_row() because the source row
1678 is not selected anymore */
1679 gtk_tree_view_get_dest_row_at_pos (GTK_TREE_VIEW (widget), x, y,
1682 /* Only allow drops IN other rows */
1683 if (!dest_row || pos == GTK_TREE_VIEW_DROP_BEFORE || pos == GTK_TREE_VIEW_DROP_AFTER)
1684 gtk_drag_finish (context, success, FALSE, time);
1686 /* Create the helper */
1687 helper = g_slice_new0 (DndHelper);
1688 helper->delete_source = delete_source;
1689 helper->source_row = gtk_tree_path_copy (source_row);
1690 helper->context = context;
1691 helper->time = time;
1693 /* Drags from the header view */
1694 if (source_widget != widget) {
1696 drag_and_drop_from_header_view (source_model,
1703 drag_and_drop_from_folder_view (source_model,
1711 gtk_tree_path_free (source_row);
1712 gtk_tree_path_free (dest_row);
1716 * We define a "drag-drop" signal handler because we do not want to
1717 * use the default one, because the default one always calls
1718 * gtk_drag_finish and we prefer to do it in the "drag-data-received"
1719 * signal handler, because there we have all the information available
1720 * to know if the dnd was a success or not.
1723 drag_drop_cb (GtkWidget *widget,
1724 GdkDragContext *context,
1732 if (!context->targets)
1735 /* Check if we're dragging a folder row */
1736 target = gtk_drag_dest_find_target (widget, context, NULL);
1738 /* Request the data from the source. */
1739 gtk_drag_get_data(widget, context, target, time);
1745 * This function expands a node of a tree view if it's not expanded
1746 * yet. Not sure why it needs the threads stuff, but gtk+`example code
1747 * does that, so that's why they're here.
1750 expand_row_timeout (gpointer data)
1752 GtkTreeView *tree_view = data;
1753 GtkTreePath *dest_path = NULL;
1754 GtkTreeViewDropPosition pos;
1755 gboolean result = FALSE;
1757 GDK_THREADS_ENTER ();
1759 gtk_tree_view_get_drag_dest_row (tree_view,
1764 (pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
1765 pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE)) {
1766 gtk_tree_view_expand_row (tree_view, dest_path, FALSE);
1767 gtk_tree_path_free (dest_path);
1771 gtk_tree_path_free (dest_path);
1776 GDK_THREADS_LEAVE ();
1782 * This function is called whenever the pointer is moved over a widget
1783 * while dragging some data. It installs a timeout that will expand a
1784 * node of the treeview if not expanded yet. This function also calls
1785 * gdk_drag_status in order to set the suggested action that will be
1786 * used by the "drag-data-received" signal handler to know if we
1787 * should do a move or just a copy of the data.
1790 on_drag_motion (GtkWidget *widget,
1791 GdkDragContext *context,
1797 GtkTreeViewDropPosition pos;
1798 GtkTreePath *dest_row;
1799 ModestFolderViewPrivate *priv;
1800 GdkDragAction suggested_action;
1801 gboolean valid_location = FALSE;
1803 priv = MODEST_FOLDER_VIEW_GET_PRIVATE (widget);
1805 if (priv->timer_expander != 0) {
1806 g_source_remove (priv->timer_expander);
1807 priv->timer_expander = 0;
1810 gtk_tree_view_get_dest_row_at_pos (GTK_TREE_VIEW (widget),
1815 /* Do not allow drops between folders */
1817 pos == GTK_TREE_VIEW_DROP_BEFORE ||
1818 pos == GTK_TREE_VIEW_DROP_AFTER) {
1819 gtk_tree_view_set_drag_dest_row(GTK_TREE_VIEW (widget), NULL, 0);
1820 gdk_drag_status(context, 0, time);
1821 valid_location = FALSE;
1824 valid_location = TRUE;
1827 /* Expand the selected row after 1/2 second */
1828 if (!gtk_tree_view_row_expanded (GTK_TREE_VIEW (widget), dest_row)) {
1829 gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget), dest_row, pos);
1830 priv->timer_expander = g_timeout_add (500, expand_row_timeout, widget);
1833 /* Select the desired action. By default we pick MOVE */
1834 suggested_action = GDK_ACTION_MOVE;
1836 if (context->actions == GDK_ACTION_COPY)
1837 gdk_drag_status(context, GDK_ACTION_COPY, time);
1838 else if (context->actions == GDK_ACTION_MOVE)
1839 gdk_drag_status(context, GDK_ACTION_MOVE, time);
1840 else if (context->actions & suggested_action)
1841 gdk_drag_status(context, suggested_action, time);
1843 gdk_drag_status(context, GDK_ACTION_DEFAULT, time);
1847 gtk_tree_path_free (dest_row);
1848 g_signal_stop_emission_by_name (widget, "drag-motion");
1849 return valid_location;
1853 /* Folder view drag types */
1854 const GtkTargetEntry folder_view_drag_types[] =
1856 { "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_WIDGET, MODEST_FOLDER_ROW },
1857 { "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_APP, MODEST_HEADER_ROW }
1861 * This function sets the treeview as a source and a target for dnd
1862 * events. It also connects all the requirede signals.
1865 setup_drag_and_drop (GtkTreeView *self)
1867 /* Set up the folder view as a dnd destination. Set only the
1868 highlight flag, otherwise gtk will have a different
1870 gtk_drag_dest_set (GTK_WIDGET (self),
1871 GTK_DEST_DEFAULT_HIGHLIGHT,
1872 folder_view_drag_types,
1873 G_N_ELEMENTS (folder_view_drag_types),
1874 GDK_ACTION_MOVE | GDK_ACTION_COPY);
1876 g_signal_connect (G_OBJECT (self),
1877 "drag_data_received",
1878 G_CALLBACK (on_drag_data_received),
1882 /* Set up the treeview as a dnd source */
1883 gtk_drag_source_set (GTK_WIDGET (self),
1885 folder_view_drag_types,
1886 G_N_ELEMENTS (folder_view_drag_types),
1887 GDK_ACTION_MOVE | GDK_ACTION_COPY);
1889 g_signal_connect (G_OBJECT (self),
1891 G_CALLBACK (on_drag_motion),
1894 g_signal_connect (G_OBJECT (self),
1896 G_CALLBACK (on_drag_data_get),
1899 g_signal_connect (G_OBJECT (self),
1901 G_CALLBACK (drag_drop_cb),
1906 * This function manages the navigation through the folders using the
1907 * keyboard or the hardware keys in the device
1910 on_key_pressed (GtkWidget *self,
1914 GtkTreeSelection *selection;
1916 GtkTreeModel *model;
1917 gboolean retval = FALSE;
1919 /* Up and Down are automatically managed by the treeview */
1920 if (event->keyval == GDK_Return) {
1921 /* Expand/Collapse the selected row */
1922 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (self));
1923 if (gtk_tree_selection_get_selected (selection, &model, &iter)) {
1926 path = gtk_tree_model_get_path (model, &iter);
1928 if (gtk_tree_view_row_expanded (GTK_TREE_VIEW (self), path))
1929 gtk_tree_view_collapse_row (GTK_TREE_VIEW (self), path);
1931 gtk_tree_view_expand_row (GTK_TREE_VIEW (self), path, FALSE);
1932 gtk_tree_path_free (path);
1934 /* No further processing */
1942 * We listen to the changes in the local folder account name key,
1943 * because we want to show the right name in the view. The local
1944 * folder account name corresponds to the device name in the Maemo
1945 * version. We do this because we do not want to query gconf on each
1946 * tree view refresh. It's better to cache it and change whenever
1950 on_configuration_key_changed (ModestConf* conf,
1952 ModestConfEvent event,
1953 ModestFolderView *self)
1955 ModestFolderViewPrivate *priv;
1960 g_return_if_fail (MODEST_IS_FOLDER_VIEW (self));
1961 priv = MODEST_FOLDER_VIEW_GET_PRIVATE(self);
1963 if (!strcmp (key, MODEST_CONF_DEVICE_NAME)) {
1964 g_free (priv->local_account_name);
1966 if (event == MODEST_CONF_EVENT_KEY_UNSET)
1967 priv->local_account_name = g_strdup (MODEST_LOCAL_FOLDERS_DEFAULT_DISPLAY_NAME);
1969 priv->local_account_name = modest_conf_get_string (modest_runtime_get_conf(),
1970 MODEST_CONF_DEVICE_NAME, NULL);
1972 /* Force a redraw */
1973 #if GTK_CHECK_VERSION(2, 8, 0) /* gtk_tree_view_column_queue_resize is only available in GTK+ 2.8 */
1974 GtkTreeViewColumn * tree_column = gtk_tree_view_get_column (GTK_TREE_VIEW (self),
1975 TNY_GTK_FOLDER_STORE_TREE_MODEL_NAME_COLUMN);
1976 gtk_tree_view_column_queue_resize (tree_column);
1982 modest_folder_view_set_style (ModestFolderView *self,
1983 ModestFolderViewStyle style)
1985 ModestFolderViewPrivate *priv;
1987 g_return_if_fail (self);
1989 priv = MODEST_FOLDER_VIEW_GET_PRIVATE(self);
1991 priv->style = style;
1995 modest_folder_view_set_account_id_of_visible_server_account (ModestFolderView *self,
1996 const gchar *account_id)
1998 ModestFolderViewPrivate *priv;
1999 GtkTreeModel *model;
2001 g_return_if_fail (self);
2003 priv = MODEST_FOLDER_VIEW_GET_PRIVATE(self);
2005 /* This will be used by the filter_row callback,
2006 * to decided which rows to show: */
2007 if (priv->visible_account_id) {
2008 g_free (priv->visible_account_id);
2009 priv->visible_account_id = NULL;
2012 priv->visible_account_id = g_strdup (account_id);
2015 model = gtk_tree_view_get_model (GTK_TREE_VIEW (self));
2016 if (GTK_IS_TREE_MODEL_FILTER (model))
2017 gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (model));
2019 /* Save settings to gconf */
2020 modest_widget_memory_save (modest_runtime_get_conf (), G_OBJECT(self),
2021 MODEST_CONF_FOLDER_VIEW_KEY);
2025 modest_folder_view_get_account_id_of_visible_server_account (ModestFolderView *self)
2027 ModestFolderViewPrivate *priv;
2029 g_return_val_if_fail (self, NULL);
2031 priv = MODEST_FOLDER_VIEW_GET_PRIVATE(self);
2033 return (const gchar *) priv->visible_account_id;
2037 find_inbox_iter (GtkTreeModel *model, GtkTreeIter *iter, GtkTreeIter *inbox_iter)
2041 TnyFolderType type = TNY_FOLDER_TYPE_UNKNOWN;
2043 gtk_tree_model_get (model, iter,
2044 TNY_GTK_FOLDER_STORE_TREE_MODEL_TYPE_COLUMN,
2047 gboolean result = FALSE;
2048 if (type == TNY_FOLDER_TYPE_INBOX) {
2052 *inbox_iter = *iter;
2056 if (gtk_tree_model_iter_children (model, &child, iter)) {
2057 if (find_inbox_iter (model, &child, inbox_iter))
2061 } while (gtk_tree_model_iter_next (model, iter));
2070 modest_folder_view_select_first_inbox_or_local (ModestFolderView *self)
2072 GtkTreeModel *model;
2073 GtkTreeIter iter, inbox_iter;
2074 GtkTreeSelection *sel;
2075 GtkTreePath *path = NULL;
2077 model = gtk_tree_view_get_model (GTK_TREE_VIEW (self));
2081 expand_root_items (self);
2082 sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (self));
2084 gtk_tree_model_get_iter_first (model, &iter);
2086 if (find_inbox_iter (model, &iter, &inbox_iter))
2087 path = gtk_tree_model_get_path (model, &inbox_iter);
2089 path = gtk_tree_path_new_first ();
2091 /* Select the row and free */
2092 gtk_tree_view_set_cursor (GTK_TREE_VIEW (self), path, NULL, FALSE);
2093 gtk_tree_path_free (path);
2099 find_folder_iter (GtkTreeModel *model, GtkTreeIter *iter, GtkTreeIter *folder_iter,
2104 TnyFolderType type = TNY_FOLDER_TYPE_UNKNOWN;
2105 TnyFolder* a_folder;
2108 gtk_tree_model_get (model, iter,
2109 TNY_GTK_FOLDER_STORE_TREE_MODEL_INSTANCE_COLUMN, &a_folder,
2110 TNY_GTK_FOLDER_STORE_TREE_MODEL_NAME_COLUMN, &name,
2111 TNY_GTK_FOLDER_STORE_TREE_MODEL_TYPE_COLUMN, &type,
2114 g_debug ("===> %s (%p ---- %p)", name, a_folder, folder);
2117 if (folder == a_folder) {
2118 g_object_unref (a_folder);
2119 *folder_iter = *iter;
2122 g_object_unref (a_folder);
2124 if (gtk_tree_model_iter_children (model, &child, iter)) {
2125 if (find_folder_iter (model, &child, folder_iter, folder))
2129 } while (gtk_tree_model_iter_next (model, iter));
2136 on_row_changed_maybe_select_folder (GtkTreeModel *tree_model, GtkTreePath *path, GtkTreeIter *iter,
2137 ModestFolderView *self)
2139 ModestFolderViewPrivate *priv = NULL;
2140 GtkTreeSelection *sel;
2142 if (!MODEST_IS_FOLDER_VIEW(self))
2145 priv = MODEST_FOLDER_VIEW_GET_PRIVATE (self);
2147 if (priv->folder_to_select) {
2149 if (!modest_folder_view_select_folder (self, priv->folder_to_select,
2152 path = gtk_tree_model_get_path (tree_model, iter);
2153 gtk_tree_view_expand_to_path (GTK_TREE_VIEW(self), path);
2155 sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (self));
2157 gtk_tree_selection_select_iter (sel, iter);
2158 gtk_tree_view_set_cursor (GTK_TREE_VIEW(self), path, NULL, FALSE);
2160 gtk_tree_path_free (path);
2163 g_object_unref (priv->folder_to_select);
2164 priv->folder_to_select = NULL;
2170 modest_folder_view_select_folder (ModestFolderView *self, TnyFolder *folder,
2171 gboolean after_change)
2173 GtkTreeModel *model;
2174 GtkTreeIter iter, folder_iter;
2175 GtkTreeSelection *sel;
2176 ModestFolderViewPrivate *priv = NULL;
2178 g_return_val_if_fail (MODEST_IS_FOLDER_VIEW (self), FALSE);
2179 g_return_val_if_fail (TNY_IS_FOLDER (folder), FALSE);
2181 priv = MODEST_FOLDER_VIEW_GET_PRIVATE (self);
2185 sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (self));
2186 gtk_tree_selection_unselect_all (sel);
2188 if (priv->folder_to_select)
2189 g_object_unref(priv->folder_to_select);
2190 priv->folder_to_select = TNY_FOLDER(g_object_ref(folder));
2194 model = gtk_tree_view_get_model (GTK_TREE_VIEW (self));
2199 gtk_tree_model_get_iter_first (model, &iter);
2200 if (find_folder_iter (model, &iter, &folder_iter, folder)) {
2203 path = gtk_tree_model_get_path (model, &folder_iter);
2204 gtk_tree_view_expand_to_path (GTK_TREE_VIEW(self), path);
2206 sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (self));
2207 gtk_tree_selection_select_iter (sel, &folder_iter);
2208 gtk_tree_view_set_cursor (GTK_TREE_VIEW(self), path, NULL, FALSE);
2210 gtk_tree_path_free (path);
2218 modest_folder_view_copy_selection (ModestFolderView *folder_view)
2220 /* Copy selection */
2221 _clipboard_set_selected_data (folder_view, FALSE);
2225 modest_folder_view_cut_selection (ModestFolderView *folder_view)
2227 ModestFolderViewPrivate *priv = NULL;
2228 GtkTreeModel *model = NULL;
2229 const gchar **hidding = NULL;
2230 guint i, n_selected;
2232 g_return_if_fail (MODEST_IS_FOLDER_VIEW (folder_view));
2233 priv = MODEST_FOLDER_VIEW_GET_PRIVATE (folder_view);
2235 /* Copy selection */
2236 if (!_clipboard_set_selected_data (folder_view, TRUE))
2239 /* Get hidding ids */
2240 hidding = modest_email_clipboard_get_hidding_ids (priv->clipboard, &n_selected);
2242 /* Clear hidding array created by previous cut operation */
2243 _clear_hidding_filter (MODEST_FOLDER_VIEW (folder_view));
2245 /* Copy hidding array */
2246 priv->n_selected = n_selected;
2247 priv->hidding_ids = g_malloc0(sizeof(gchar *) * n_selected);
2248 for (i=0; i < n_selected; i++)
2249 priv->hidding_ids[i] = g_strdup(hidding[i]);
2251 /* Hide cut folders */
2252 model = gtk_tree_view_get_model (GTK_TREE_VIEW (folder_view));
2253 gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (model));
2257 modest_folder_view_show_non_move_folders (ModestFolderView *folder_view,
2260 ModestFolderViewPrivate* priv = MODEST_FOLDER_VIEW_GET_PRIVATE(folder_view);
2261 priv->show_non_move = show;
2262 modest_folder_view_update_model(folder_view,
2263 TNY_ACCOUNT_STORE(modest_runtime_get_account_store()));
2266 /* Returns FALSE if it did not selected anything */
2268 _clipboard_set_selected_data (ModestFolderView *folder_view,
2271 ModestFolderViewPrivate *priv = NULL;
2272 TnyFolderStore *folder = NULL;
2273 gboolean retval = FALSE;
2275 g_return_val_if_fail (MODEST_IS_FOLDER_VIEW (folder_view), FALSE);
2276 priv = MODEST_FOLDER_VIEW_GET_PRIVATE (folder_view);
2278 /* Set selected data on clipboard */
2279 g_return_val_if_fail (MODEST_IS_EMAIL_CLIPBOARD (priv->clipboard), FALSE);
2280 folder = modest_folder_view_get_selected (folder_view);
2282 /* Do not allow to select an account */
2283 if (TNY_IS_FOLDER (folder)) {
2284 modest_email_clipboard_set_data (priv->clipboard, TNY_FOLDER(folder), NULL, delete);
2289 g_object_unref (folder);
2295 _clear_hidding_filter (ModestFolderView *folder_view)
2297 ModestFolderViewPrivate *priv;
2300 g_return_if_fail (MODEST_IS_FOLDER_VIEW (folder_view));
2301 priv = MODEST_FOLDER_VIEW_GET_PRIVATE(folder_view);
2303 if (priv->hidding_ids != NULL) {
2304 for (i=0; i < priv->n_selected; i++)
2305 g_free (priv->hidding_ids[i]);
2306 g_free(priv->hidding_ids);