+
+static void
+notify_filter_change_destroy (gpointer data)
+{
+ NotifyFilterInfo *info = (NotifyFilterInfo *) data;
+ ModestHeaderViewPrivate *priv;
+
+ priv = MODEST_HEADER_VIEW_GET_PRIVATE (info->self);
+ priv->status_timeout = 0;
+
+ g_object_unref (info->self);
+ g_object_unref (info->folder);
+ g_slice_free (NotifyFilterInfo, info);
+}
+
+static gboolean
+filter_row (GtkTreeModel *model,
+ GtkTreeIter *iter,
+ gpointer user_data)
+{
+ ModestHeaderViewPrivate *priv = NULL;
+ TnyHeaderFlags flags;
+ TnyHeader *header = NULL;
+ guint i;
+ gchar *id = NULL;
+ gboolean visible = TRUE;
+ gboolean found = FALSE;
+ GValue value = {0,};
+ HeaderViewStatus old_status;
+
+ g_return_val_if_fail (MODEST_IS_HEADER_VIEW (user_data), FALSE);
+ priv = MODEST_HEADER_VIEW_GET_PRIVATE (user_data);
+
+ /* Get header from model */
+ gtk_tree_model_get_value (model, iter, TNY_GTK_HEADER_LIST_MODEL_FLAGS_COLUMN, &value);
+ flags = (TnyHeaderFlags) g_value_get_int (&value);
+ g_value_unset (&value);
+ gtk_tree_model_get_value (model, iter, TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN, &value);
+ header = (TnyHeader *) g_value_get_object (&value);
+ g_value_unset (&value);
+
+ /* Hide deleted and mark as deleted heders */
+ if (flags & TNY_HEADER_FLAG_DELETED ||
+ flags & TNY_HEADER_FLAG_EXPUNGED) {
+ visible = FALSE;
+ goto frees;
+ }
+
+ /* If no data on clipboard, return always TRUE */
+ if (modest_email_clipboard_cleared(priv->clipboard)) {
+ visible = TRUE;
+ goto frees;
+ }
+
+ /* Get message id from header (ensure is a valid id) */
+ if (!header) {
+ visible = FALSE;
+ goto frees;
+ }
+
+ /* Check hiding */
+ if (priv->hidding_ids != NULL) {
+ id = tny_header_dup_message_id (header);
+ for (i=0; i < priv->n_selected && !found; i++)
+ if (priv->hidding_ids[i] != NULL && id != NULL)
+ found = (!strcmp (priv->hidding_ids[i], id));
+
+ visible = !found;
+ g_free(id);
+ }
+
+ frees:
+ old_status = priv->status;
+ priv->status = ((gboolean) priv->status) && !visible;
+ if ((priv->notify_status) && (priv->status != old_status)) {
+ NotifyFilterInfo *info;
+
+ if (priv->status_timeout)
+ g_source_remove (priv->status_timeout);
+
+ info = g_slice_new0 (NotifyFilterInfo);
+ info->self = g_object_ref (G_OBJECT (user_data));
+ info->folder = tny_header_get_folder (header);
+ priv->status_timeout = g_timeout_add_full (G_PRIORITY_DEFAULT, 1000,
+ notify_filter_change,
+ info,
+ notify_filter_change_destroy);
+ }
+
+ return visible;
+}
+
+static void
+_clear_hidding_filter (ModestHeaderView *header_view)
+{
+ ModestHeaderViewPrivate *priv = NULL;
+ 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);
+ }
+}
+
+void
+modest_header_view_refilter (ModestHeaderView *header_view)
+{
+ GtkTreeModel *model = NULL;
+ ModestHeaderViewPrivate *priv = NULL;
+
+ g_return_if_fail (header_view && MODEST_IS_HEADER_VIEW (header_view));
+ priv = MODEST_HEADER_VIEW_GET_PRIVATE(header_view);
+
+ /* Hide cut headers */
+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (header_view));
+ if (GTK_IS_TREE_MODEL_FILTER (model)) {
+ priv->status = HEADER_VIEW_INIT;
+ gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (model));
+ }
+}
+
+/*
+ * Called when an account is removed. If I'm showing a folder of the
+ * account that has been removed then clear the view
+ */
+static void
+on_account_removed (TnyAccountStore *self,
+ TnyAccount *account,
+ gpointer user_data)
+{
+ ModestHeaderViewPrivate *priv = NULL;
+
+ /* Ignore changes in transport accounts */
+ if (TNY_IS_TRANSPORT_ACCOUNT (account))
+ return;
+
+ priv = MODEST_HEADER_VIEW_GET_PRIVATE (user_data);
+
+ if (priv->folder) {
+ TnyAccount *my_account;
+
+ my_account = tny_folder_get_account (priv->folder);
+ if (my_account == account)
+ modest_header_view_clear (MODEST_HEADER_VIEW (user_data));
+ g_object_unref (my_account);
+ }
+}
+
+void
+modest_header_view_add_observer(ModestHeaderView *header_view,
+ ModestHeaderViewObserver *observer)
+{
+ ModestHeaderViewPrivate *priv;
+
+ g_return_if_fail (header_view && MODEST_IS_HEADER_VIEW(header_view));
+ g_return_if_fail (observer && MODEST_IS_HEADER_VIEW_OBSERVER(observer));
+
+ priv = MODEST_HEADER_VIEW_GET_PRIVATE(header_view);
+
+ g_mutex_lock(priv->observer_list_lock);
+ priv->observer_list = g_slist_prepend(priv->observer_list, observer);
+ g_mutex_unlock(priv->observer_list_lock);
+}
+
+void
+modest_header_view_remove_observer(ModestHeaderView *header_view,
+ ModestHeaderViewObserver *observer)
+{
+ ModestHeaderViewPrivate *priv;
+
+ g_return_if_fail (header_view && MODEST_IS_HEADER_VIEW(header_view));
+ g_return_if_fail (observer && MODEST_IS_HEADER_VIEW_OBSERVER(observer));
+
+ priv = MODEST_HEADER_VIEW_GET_PRIVATE(header_view);
+
+ g_mutex_lock(priv->observer_list_lock);
+ priv->observer_list = g_slist_remove(priv->observer_list, observer);
+ g_mutex_unlock(priv->observer_list_lock);
+}
+
+static void
+modest_header_view_notify_observers(ModestHeaderView *header_view,
+ GtkTreeModel *model,
+ const gchar *tny_folder_id)
+{
+ ModestHeaderViewPrivate *priv = NULL;
+ GSList *iter;
+ ModestHeaderViewObserver *observer;
+
+
+ g_return_if_fail (header_view && MODEST_IS_HEADER_VIEW(header_view));
+
+ priv = MODEST_HEADER_VIEW_GET_PRIVATE(header_view);
+
+ g_mutex_lock(priv->observer_list_lock);
+ iter = priv->observer_list;
+ while(iter != NULL){
+ observer = MODEST_HEADER_VIEW_OBSERVER(iter->data);
+ modest_header_view_observer_update(observer, model,
+ tny_folder_id);
+ iter = g_slist_next(iter);
+ }
+ g_mutex_unlock(priv->observer_list_lock);
+}
+