X-Git-Url: http://git.maemo.org/git/?p=modest;a=blobdiff_plain;f=src%2Fwidgets%2Fmodest-header-view.c;h=8fea86a363802373daeab39056283d83ff57b489;hp=c4f239df866433363b271d8aa429b92a8da9cc7f;hb=102da45ebfdda4bcd3fccc166342bee474f0c1bc;hpb=32aa324fb6312e9a86f9b244f63178fa1807043d diff --git a/src/widgets/modest-header-view.c b/src/widgets/modest-header-view.c index c4f239d..8fea86a 100644 --- a/src/widgets/modest-header-view.c +++ b/src/widgets/modest-header-view.c @@ -38,6 +38,8 @@ #include #include +#include + #include #include #include @@ -49,16 +51,25 @@ static void modest_header_view_class_init (ModestHeaderViewClass *klass); static void modest_header_view_init (ModestHeaderView *obj); static void modest_header_view_finalize (GObject *obj); +static void modest_header_view_dispose (GObject *obj); -static gboolean on_header_clicked (GtkWidget *widget, - GdkEventButton *event, - gpointer user_data); +static void on_header_row_activated (GtkTreeView *treeview, GtkTreePath *path, + GtkTreeViewColumn *column, gpointer userdata); static gint cmp_rows (GtkTreeModel *tree_model, GtkTreeIter *iter1, GtkTreeIter *iter2, gpointer user_data); +static gint cmp_subject_rows (GtkTreeModel *tree_model, + GtkTreeIter *iter1, + GtkTreeIter *iter2, + gpointer user_data); + +static gboolean filter_row (GtkTreeModel *model, + GtkTreeIter *iter, + gpointer data); + static void on_selection_changed (GtkTreeSelection *sel, gpointer user_data); @@ -75,6 +86,11 @@ static void folder_monitor_update (TnyFolderObserver *self, static void tny_folder_observer_init (TnyFolderObserverIface *klass); +static void _clipboard_set_selected_data (ModestHeaderView *header_view, gboolean delete); + +static void _clear_hidding_filter (ModestHeaderView *header_view); + + typedef struct _ModestHeaderViewPrivate ModestHeaderViewPrivate; struct _ModestHeaderViewPrivate { TnyFolder *folder; @@ -83,12 +99,26 @@ struct _ModestHeaderViewPrivate { TnyFolderMonitor *monitor; GMutex *observers_lock; + /* not unref this object, its a singlenton */ + ModestEmailClipboard *clipboard; + + /* Filter tree model */ + gchar **hidding_ids; + guint n_selected; + gint sort_colid[2][TNY_FOLDER_TYPE_NUM]; gint sort_type[2][TNY_FOLDER_TYPE_NUM]; }; +typedef struct _HeadersCountChangedHelper HeadersCountChangedHelper; +struct _HeadersCountChangedHelper { + ModestHeaderView *self; + TnyFolderChange *change; +}; + + #define MODEST_HEADER_VIEW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \ MODEST_TYPE_HEADER_VIEW, \ ModestHeaderViewPrivate)) @@ -101,7 +131,7 @@ enum { HEADER_SELECTED_SIGNAL, HEADER_ACTIVATED_SIGNAL, ITEM_NOT_FOUND_SIGNAL, - STATUS_UPDATE_SIGNAL, + MSG_COUNT_CHANGED_SIGNAL, LAST_SIGNAL }; @@ -155,6 +185,7 @@ modest_header_view_class_init (ModestHeaderViewClass *klass) parent_class = g_type_class_peek_parent (klass); gobject_class->finalize = modest_header_view_finalize; + gobject_class->dispose = modest_header_view_dispose; g_type_class_add_private (gobject_class, sizeof(ModestHeaderViewPrivate)); @@ -186,14 +217,14 @@ modest_header_view_class_init (ModestHeaderViewClass *klass) g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT); - signals[STATUS_UPDATE_SIGNAL] = - g_signal_new ("status_update", + signals[MSG_COUNT_CHANGED_SIGNAL] = + g_signal_new ("msg_count_changed", G_TYPE_FROM_CLASS (gobject_class), G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (ModestHeaderViewClass,status_update), + G_STRUCT_OFFSET (ModestHeaderViewClass, msg_count_changed), NULL, NULL, - modest_marshal_VOID__STRING_INT_INT, - G_TYPE_NONE, 3, G_TYPE_STRING, G_TYPE_INT, G_TYPE_INT); + modest_marshal_VOID__POINTER_POINTER, + G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_POINTER); } static void @@ -248,7 +279,7 @@ remove_all_columns (ModestHeaderView *obj) gboolean modest_header_view_set_columns (ModestHeaderView *self, const GList *columns, TnyFolderType type) { - GtkTreeModel *sortable; + GtkTreeModel *tree_filter, *sortable; GtkTreeViewColumn *column=NULL; GtkTreeSelection *selection = NULL; GtkCellRenderer *renderer_msgtype,*renderer_header, @@ -310,7 +341,9 @@ modest_header_view_set_columns (ModestHeaderView *self, const GList *columns, Tn selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(self)); gtk_tree_selection_set_mode(selection, GTK_SELECTION_MULTIPLE); - sortable = gtk_tree_view_get_model (GTK_TREE_VIEW (self)); +/* sortable = gtk_tree_view_get_model (GTK_TREE_VIEW (self)); */ + tree_filter = gtk_tree_view_get_model (GTK_TREE_VIEW (self)); + sortable = gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER(tree_filter)); /* Add new columns */ for (cursor = columns; cursor; cursor = g_list_next(cursor)) { @@ -436,6 +469,10 @@ modest_header_view_set_columns (ModestHeaderView *self, const GList *columns, Tn TNY_GTK_HEADER_LIST_MODEL_FLAGS_COLUMN, (GtkTreeIterCompareFunc) cmp_rows, compact_column, NULL); + gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (sortable), + TNY_GTK_HEADER_LIST_MODEL_SUBJECT_COLUMN, + (GtkTreeIterCompareFunc) cmp_subject_rows, + compact_column, NULL); } @@ -455,6 +492,10 @@ modest_header_view_init (ModestHeaderView *obj) priv->monitor = NULL; priv->observers_lock = g_mutex_new (); + priv->clipboard = modest_runtime_get_email_clipboard (); + priv->hidding_ids = NULL; + priv->n_selected = 0; + /* Sort parameters */ for (j=0; j < 2; j++) { for (i=0; i < TNY_FOLDER_TYPE_NUM; i++) { @@ -467,6 +508,26 @@ modest_header_view_init (ModestHeaderView *obj) } static void +modest_header_view_dispose (GObject *obj) +{ + ModestHeaderView *self; + ModestHeaderViewPrivate *priv; + + self = MODEST_HEADER_VIEW(obj); + priv = MODEST_HEADER_VIEW_GET_PRIVATE(self); + + if (priv->folder) { + tny_folder_remove_observer (priv->folder, TNY_FOLDER_OBSERVER (obj)); + g_object_unref (G_OBJECT (priv->folder)); + priv->folder = NULL; + } + + G_OBJECT_CLASS(parent_class)->dispose (obj); +} + + + +static void modest_header_view_finalize (GObject *obj) { ModestHeaderView *self; @@ -483,11 +544,8 @@ modest_header_view_finalize (GObject *obj) g_mutex_unlock (priv->observers_lock); g_mutex_free (priv->observers_lock); - if (priv->folder) { - tny_folder_remove_observer (priv->folder, TNY_FOLDER_OBSERVER (obj)); - g_object_unref (G_OBJECT (priv->folder)); - priv->folder = NULL; - } + /* Clear hidding array created by cut operation */ + _clear_hidding_filter (MODEST_HEADER_VIEW (obj)); G_OBJECT_CLASS(parent_class)->finalize (obj); } @@ -509,7 +567,7 @@ modest_header_view_new (TnyFolder *folder, ModestHeaderViewStyle style) priv = MODEST_HEADER_VIEW_GET_PRIVATE(self); modest_header_view_set_style (self, style); - modest_header_view_set_folder (self, NULL); +/* modest_header_view_set_folder (self, NULL, NULL, NULL); */ gtk_tree_view_columns_autosize (GTK_TREE_VIEW(obj)); gtk_tree_view_set_fixed_height_mode (GTK_TREE_VIEW(obj),TRUE); @@ -522,8 +580,8 @@ modest_header_view_new (TnyFolder *folder, ModestHeaderViewStyle style) g_signal_connect (sel, "changed", G_CALLBACK(on_selection_changed), self); - g_signal_connect (self, "button-press-event", - G_CALLBACK(on_header_clicked), NULL); + g_signal_connect (self, "row-activated", + G_CALLBACK (on_header_row_activated), NULL); g_signal_connect (self, "focus-in-event", G_CALLBACK(on_focus_in), NULL); @@ -726,21 +784,17 @@ modest_header_view_get_style (ModestHeaderView *self) static void modest_header_view_set_model (GtkTreeView *header_view, GtkTreeModel *model) { - GtkTreeModel *old_model_sort = gtk_tree_view_get_model (GTK_TREE_VIEW (header_view)); - - if (old_model_sort && GTK_IS_TREE_MODEL_SORT (old_model_sort)) { - GtkTreeModel *old_model; - ModestHeaderViewPrivate *priv; - - priv = MODEST_HEADER_VIEW_GET_PRIVATE (header_view); - old_model = gtk_tree_model_sort_get_model (GTK_TREE_MODEL_SORT (old_model_sort)); - - /* Set new model */ - gtk_tree_view_set_model (header_view, model); - } else - gtk_tree_view_set_model (header_view, model); - - return; +/* GtkTreeModel *old_model_sort = gtk_tree_view_get_model (GTK_TREE_VIEW (header_view)); */ +/* if (old_model_sort && GTK_IS_TREE_MODEL_SORT (old_model_sort)) { */ +/* GtkTreeModel *old_model; */ +/* ModestHeaderViewPrivate *priv; */ +/* priv = MODEST_HEADER_VIEW_GET_PRIVATE (header_view); */ +/* old_model = gtk_tree_model_sort_get_model (GTK_TREE_MODEL_SORT (old_model_sort)); */ + +/* /\* Set new model *\/ */ +/* gtk_tree_view_set_model (header_view, model); */ +/* } else */ + gtk_tree_view_set_model (header_view, model); } TnyFolder* @@ -762,7 +816,7 @@ modest_header_view_set_folder_intern (ModestHeaderView *self, TnyFolder *folder) TnyList *headers; ModestHeaderViewPrivate *priv; GList *cols, *cursor; - GtkTreeModel *sortable; + GtkTreeModel *filter_model, *sortable; guint sort_colid; GtkSortType sort_type; @@ -789,6 +843,14 @@ modest_header_view_set_folder_intern (ModestHeaderView *self, TnyFolder *folder) sortable = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL(headers)); g_object_unref (G_OBJECT (headers)); + /* Create a tree model filter to hide and show rows for cut operations */ + filter_model = gtk_tree_model_filter_new (sortable, NULL); + gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter_model), + filter_row, + self, + NULL); + g_object_unref (G_OBJECT (sortable)); + /* install our special sorting functions */ cursor = cols = gtk_tree_view_get_columns (GTK_TREE_VIEW(self)); @@ -804,11 +866,17 @@ modest_header_view_set_folder_intern (ModestHeaderView *self, TnyFolder *folder) TNY_GTK_HEADER_LIST_MODEL_FLAGS_COLUMN, (GtkTreeIterCompareFunc) cmp_rows, cols->data, NULL); + gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE(sortable), + TNY_GTK_HEADER_LIST_MODEL_SUBJECT_COLUMN, + (GtkTreeIterCompareFunc) cmp_subject_rows, + cols->data, NULL); } /* Set new model */ - modest_header_view_set_model (GTK_TREE_VIEW (self), sortable); - g_object_unref (G_OBJECT (sortable)); + modest_header_view_set_model (GTK_TREE_VIEW (self), filter_model); + g_object_unref (G_OBJECT (filter_model)); +/* modest_header_view_set_model (GTK_TREE_VIEW (self), sortable); */ +/* g_object_unref (G_OBJECT (sortable)); */ /* Free */ g_list_free (cols); @@ -820,12 +888,14 @@ modest_header_view_sort_by_column_id (ModestHeaderView *self, GtkSortType sort_type) { ModestHeaderViewPrivate *priv = NULL; - GtkTreeModel *sortable = NULL; + GtkTreeModel *tree_filter, *sortable = NULL; TnyFolderType type; /* Get model and private data */ priv = MODEST_HEADER_VIEW_GET_PRIVATE(self); - sortable = gtk_tree_view_get_model (GTK_TREE_VIEW (self)); + tree_filter = gtk_tree_view_get_model (GTK_TREE_VIEW (self)); + sortable = gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER(tree_filter)); +/* sortable = gtk_tree_view_get_model (GTK_TREE_VIEW (self)); */ /* Sort tree model */ type = modest_tny_folder_guess_folder_type (priv->folder); @@ -884,22 +954,32 @@ modest_header_view_get_sort_type (ModestHeaderView *self, } void -modest_header_view_set_folder (ModestHeaderView *self, TnyFolder *folder) +modest_header_view_set_folder (ModestHeaderView *self, + TnyFolder *folder, + RefreshAsyncUserCallback callback, + gpointer user_data) { ModestHeaderViewPrivate *priv; - + ModestWindowMgr *mgr = NULL; + GObject *source = NULL; + priv = MODEST_HEADER_VIEW_GET_PRIVATE(self); if (priv->folder) { g_mutex_lock (priv->observers_lock); tny_folder_remove_observer (priv->folder, TNY_FOLDER_OBSERVER (self)); g_object_unref (priv->folder); +/* g_print ("---------- REMAINING %d\n", ((GObject*)priv->folder)->ref_count); */ priv->folder = NULL; g_mutex_unlock (priv->observers_lock); } if (folder) { - ModestMailOperation *mail_op; + ModestMailOperation *mail_op = NULL; + + /* Get main window to use it as source of mail operation */ + mgr = modest_runtime_get_window_mgr (); + source = G_OBJECT (modest_window_mgr_get_main_window (modest_runtime_get_window_mgr ())); /* Set folder in the model */ modest_header_view_set_folder_intern (self, folder); @@ -910,17 +990,18 @@ modest_header_view_set_folder (ModestHeaderView *self, TnyFolder *folder) /* no message selected */ g_signal_emit (G_OBJECT(self), signals[HEADER_SELECTED_SIGNAL], 0, NULL); - /* Create the mail operation */ - mail_op = modest_mail_operation_new (MODEST_MAIL_OPERATION_TYPE_RECEIVE, NULL); + /* Create the mail operation (source will be the parent widget) */ + mail_op = modest_mail_operation_new (MODEST_MAIL_OPERATION_TYPE_RECEIVE, source); modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), mail_op); /* Refresh the folder asynchronously */ - modest_mail_operation_refresh_folder (mail_op, folder); + modest_mail_operation_refresh_folder (mail_op, folder, + callback, + user_data); /* Free */ g_object_unref (mail_op); - } else { g_mutex_lock (priv->observers_lock); @@ -935,25 +1016,23 @@ modest_header_view_set_folder (ModestHeaderView *self, TnyFolder *folder) } } -static gboolean -on_header_clicked (GtkWidget *widget, GdkEventButton *event, gpointer user_data) +static void +on_header_row_activated (GtkTreeView *treeview, GtkTreePath *path, + GtkTreeViewColumn *column, gpointer userdata) { ModestHeaderView *self = NULL; ModestHeaderViewPrivate *priv = NULL; - GtkTreePath *path = NULL; GtkTreeIter iter; GtkTreeModel *model = NULL; TnyHeader *header; - /* ignore everything but doubleclick */ - if (event->type != GDK_2BUTTON_PRESS) - return FALSE; - self = MODEST_HEADER_VIEW (widget); + self = MODEST_HEADER_VIEW (treeview); priv = MODEST_HEADER_VIEW_GET_PRIVATE(self); + + model = gtk_tree_view_get_model (treeview); - path = get_selected_row (GTK_TREE_VIEW(self), &model); if ((path == NULL) || (!gtk_tree_model_get_iter(model, &iter, path))) - return FALSE; + return; /* get the first selected item */ gtk_tree_model_get (model, &iter, @@ -966,12 +1045,9 @@ on_header_clicked (GtkWidget *widget, GdkEventButton *event, gpointer user_data) /* Free */ g_object_unref (G_OBJECT (header)); - gtk_tree_path_free(path); - return TRUE; } - static void on_selection_changed (GtkTreeSelection *sel, gpointer user_data) { @@ -981,6 +1057,7 @@ on_selection_changed (GtkTreeSelection *sel, gpointer user_data) GtkTreeIter iter; ModestHeaderView *self; ModestHeaderViewPrivate *priv; + GList *selected = NULL; g_return_if_fail (sel); g_return_if_fail (user_data); @@ -988,7 +1065,9 @@ on_selection_changed (GtkTreeSelection *sel, gpointer user_data) self = MODEST_HEADER_VIEW (user_data); priv = MODEST_HEADER_VIEW_GET_PRIVATE(self); - path = get_selected_row (GTK_TREE_VIEW(self), &model); + selected = gtk_tree_selection_get_selected_rows (sel, &model); + if (selected != NULL) + path = (GtkTreePath *) selected->data; if ((path == NULL) || (!gtk_tree_model_get_iter(model, &iter, path))) return; /* msg was _un_selected */ @@ -1029,19 +1108,19 @@ cmp_rows (GtkTreeModel *tree_model, GtkTreeIter *iter1, GtkTreeIter *iter2, gint t1, t2; gint val1, val2; gint cmp; - static int counter = 0; +/* static int counter = 0; */ g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN(user_data), 0); /* col_id = gtk_tree_sortable_get_sort_column_id (GTK_TREE_SORTABLE (tree_model)); */ col_id = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(user_data), MODEST_HEADER_VIEW_FLAG_SORT)); - if (!(++counter % 100)) { - GObject *header_view = g_object_get_data(G_OBJECT(user_data), - MODEST_HEADER_VIEW_PTR); - g_signal_emit (header_view, - signals[STATUS_UPDATE_SIGNAL], - 0, _("Sorting..."), 0, 0); - } +/* if (!(++counter % 100)) { */ +/* GObject *header_view = g_object_get_data(G_OBJECT(user_data), */ +/* MODEST_HEADER_VIEW_PTR); */ +/* g_signal_emit (header_view, */ +/* signals[STATUS_UPDATE_SIGNAL], */ +/* 0, _("Sorting..."), 0, 0); */ +/* } */ switch (col_id) { case TNY_HEADER_FLAG_ATTACHMENTS: @@ -1075,6 +1154,30 @@ cmp_rows (GtkTreeModel *tree_model, GtkTreeIter *iter1, GtkTreeIter *iter2, } } +static gint +cmp_subject_rows (GtkTreeModel *tree_model, GtkTreeIter *iter1, GtkTreeIter *iter2, + gpointer user_data) +{ + gint t1, t2; + gchar *val1, *val2; + gint cmp; +/* static int counter = 0; */ + + g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN(user_data), 0); + + gtk_tree_model_get (tree_model, iter1, TNY_GTK_HEADER_LIST_MODEL_SUBJECT_COLUMN, &val1, + TNY_GTK_HEADER_LIST_MODEL_DATE_SENT_TIME_T_COLUMN, &t1, -1); + gtk_tree_model_get (tree_model, iter2, TNY_GTK_HEADER_LIST_MODEL_SUBJECT_COLUMN, &val2, + TNY_GTK_HEADER_LIST_MODEL_DATE_SENT_TIME_T_COLUMN, &t2, -1); + + cmp = modest_text_utils_utf8_strcmp (val1 + modest_text_utils_get_subject_prefix_len(val1), + val2 + modest_text_utils_get_subject_prefix_len(val2), + TRUE); + g_free (val1); + g_free (val2); + return cmp; +} + /* Drag and drop stuff */ static void drag_data_get_cb (GtkWidget *widget, GdkDragContext *context, @@ -1187,6 +1290,7 @@ on_focus_in (GtkWidget *self, /* Need to get the all the rows because is selection multiple */ selected = gtk_tree_selection_get_selected_rows (selection, &model); + if (selected == NULL) return FALSE; selected_path = (GtkTreePath *) selected->data; /* Check if we need to scroll */ @@ -1218,34 +1322,203 @@ on_focus_in (GtkWidget *self, return FALSE; } +static gboolean +idle_notify_added_headers (gpointer data) +{ + modest_platform_on_new_msg (); + + return FALSE; +} + +static void +idle_notify_headers_count_changed_destroy (gpointer data) +{ + HeadersCountChangedHelper *helper = NULL; + + g_return_if_fail (data != NULL); + helper = (HeadersCountChangedHelper *) data; + + g_object_unref (helper->change); + g_slice_free (HeadersCountChangedHelper, helper); +} + +static gboolean +idle_notify_headers_count_changed (gpointer data) +{ + TnyFolder *folder = NULL; + ModestHeaderViewPrivate *priv = NULL; + HeadersCountChangedHelper *helper = NULL; + + g_return_val_if_fail (data != NULL, FALSE); + helper = (HeadersCountChangedHelper *) data; + g_return_val_if_fail (MODEST_IS_HEADER_VIEW(helper->self), FALSE); + g_return_val_if_fail (TNY_FOLDER_CHANGE(helper->change), FALSE); + + folder = tny_folder_change_get_folder (helper->change); + + priv = MODEST_HEADER_VIEW_GET_PRIVATE (helper->self); + g_mutex_lock (priv->observers_lock); + + /* Emmit signal to evaluate how headers changes affects to the window view */ + g_signal_emit (G_OBJECT(helper->self), signals[MSG_COUNT_CHANGED_SIGNAL], 0, folder, helper->change); + + /* Added or removed headers, so data sotred on cliboard are invalid */ + modest_email_clipboard_clear (priv->clipboard); + + g_mutex_unlock (priv->observers_lock); + + return FALSE; +} + static void folder_monitor_update (TnyFolderObserver *self, TnyFolderChange *change) { - ModestHeaderViewPrivate *priv = MODEST_HEADER_VIEW_GET_PRIVATE (self); TnyFolderChangeChanged changed; - - g_mutex_lock (priv->observers_lock); + HeadersCountChangedHelper *helper = NULL; changed = tny_folder_change_get_changed (change); - if (changed & TNY_FOLDER_CHANGE_CHANGED_ADDED_HEADERS) { -/* TnyIterator *iter; */ -/* TnyList *list; */ -/* /\* The added headers *\/ */ -/* list = tny_simple_list_new (); */ -/* tny_folder_change_get_added_headers (change, list); */ -/* iter = tny_list_create_iterator (list); */ -/* while (!tny_iterator_is_done (iter)) */ -/* { */ -/* TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter)); */ -/* g_object_unref (G_OBJECT (header)); */ -/* tny_iterator_next (iter); */ -/* } */ -/* g_object_unref (G_OBJECT (iter)); */ -/* g_object_unref (G_OBJECT (list)); */ - modest_platform_on_new_msg (); - } + /* We need an idle because this function is called from within + a thread, so it could cause problems if the modest platform + code calls dbus for example */ + if (changed & TNY_FOLDER_CHANGE_CHANGED_ADDED_HEADERS) + g_idle_add (idle_notify_added_headers, NULL); + + /* Check folder count */ + if ((changed & TNY_FOLDER_CHANGE_CHANGED_ADDED_HEADERS) || + (changed & TNY_FOLDER_CHANGE_CHANGED_REMOVED_HEADERS)) { + helper = g_slice_new0 (HeadersCountChangedHelper); + helper->self = MODEST_HEADER_VIEW(self); + helper->change = g_object_ref(change); + + g_idle_add_full (G_PRIORITY_DEFAULT, + idle_notify_headers_count_changed, + helper, + idle_notify_headers_count_changed_destroy); + } +} - g_mutex_unlock (priv->observers_lock); +void +modest_header_view_clear (ModestHeaderView *self) +{ + modest_header_view_set_folder (self, NULL, NULL, NULL); +} + +void +modest_header_view_copy_selection (ModestHeaderView *header_view) +{ + /* Copy selection */ + _clipboard_set_selected_data (header_view, FALSE); +} + +void +modest_header_view_cut_selection (ModestHeaderView *header_view) +{ + ModestHeaderViewPrivate *priv = NULL; + GtkTreeModel *model = NULL; + const gchar **hidding = NULL; + guint i, n_selected; + + g_return_if_fail (MODEST_IS_HEADER_VIEW (header_view)); + priv = MODEST_HEADER_VIEW_GET_PRIVATE (header_view); + + /* Copy selection */ + _clipboard_set_selected_data (header_view, TRUE); + + /* Get hidding ids */ + hidding = modest_email_clipboard_get_hidding_ids (priv->clipboard, &n_selected); + + /* Clear hidding array created by previous cut operation */ + _clear_hidding_filter (MODEST_HEADER_VIEW (header_view)); + + /* Copy hidding array */ + priv->n_selected = n_selected; + priv->hidding_ids = g_malloc0(sizeof(gchar *) * n_selected); + for (i=0; i < n_selected; i++) + priv->hidding_ids[i] = g_strdup(hidding[i]); + + /* Hide cut headers */ + model = gtk_tree_view_get_model (GTK_TREE_VIEW (header_view)); + if (GTK_IS_TREE_MODEL_FILTER (model)) + gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (model)); +} + + + + +static void +_clipboard_set_selected_data (ModestHeaderView *header_view, + gboolean delete) +{ + ModestHeaderViewPrivate *priv = NULL; + TnyList *headers = NULL; + + g_return_if_fail (MODEST_IS_HEADER_VIEW (header_view)); + priv = MODEST_HEADER_VIEW_GET_PRIVATE (header_view); + + /* Set selected data on clipboard */ + g_return_if_fail (MODEST_IS_EMAIL_CLIPBOARD (priv->clipboard)); + headers = modest_header_view_get_selected_headers (header_view); + modest_email_clipboard_set_data (priv->clipboard, priv->folder, headers, delete); + + /* Free */ + g_object_unref (headers); +} + + + +static gboolean +filter_row (GtkTreeModel *model, + GtkTreeIter *iter, + gpointer user_data) +{ + ModestHeaderViewPrivate *priv = NULL; + TnyHeader *header = NULL; + guint i; + gchar *id = NULL; + gboolean found = FALSE; + + g_return_val_if_fail (MODEST_IS_HEADER_VIEW (user_data), FALSE); + priv = MODEST_HEADER_VIEW_GET_PRIVATE (user_data); + + /* If no data on clipboard, return always TRUE */ + if (modest_email_clipboard_cleared(priv->clipboard)) return TRUE; + + /* Get header from model */ + gtk_tree_model_get (model, iter, + TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN, &header, + -1); + + /* Get message id from header (ensure is a valid id) */ + if (!header) return FALSE; + id = g_strdup(tny_header_get_message_id (header)); + + /* Check hiding */ + if (priv->hidding_ids != NULL) + for (i=0; i < priv->n_selected && !found; i++) + if (priv->hidding_ids[i] != NULL && id != NULL) + found = (!strcmp (priv->hidding_ids[i], id)); + + /* Free */ + g_object_unref (header); + g_free(id); + + return !found; +} + +static void +_clear_hidding_filter (ModestHeaderView *header_view) +{ + ModestHeaderViewPrivate *priv; + guint i; + + g_return_if_fail (MODEST_IS_HEADER_VIEW (header_view)); + priv = MODEST_HEADER_VIEW_GET_PRIVATE(header_view); + + if (priv->hidding_ids != NULL) { + for (i=0; i < priv->n_selected; i++) + g_free (priv->hidding_ids[i]); + g_free(priv->hidding_ids); + } }