[gtksourceview/gtksourcecompletion] Implemented asynchronous filtering



commit e1fc74f4a460002d1eeeffaca3827d44f2e14f0b
Author: Jesse van den Kieboom <jesse icecrew nl>
Date:   Wed Apr 22 00:00:59 2009 +0200

    Implemented asynchronous filtering
---
 gtksourceview/gtksourcecompletion.c      |   19 ++--
 gtksourceview/gtksourcecompletionmodel.c |  151 ++++++++++++++++++++++++------
 gtksourceview/gtksourcecompletionmodel.h |    3 +-
 3 files changed, 134 insertions(+), 39 deletions(-)

diff --git a/gtksourceview/gtksourcecompletion.c b/gtksourceview/gtksourcecompletion.c
index cbe42c6..ec99cb6 100644
--- a/gtksourceview/gtksourcecompletion.c
+++ b/gtksourceview/gtksourcecompletion.c
@@ -76,7 +76,6 @@ enum
 	TEXT_VIEW_BUTTON_PRESS,
 	TEXT_BUFFER_DELETE_RANGE,
 	TEXT_BUFFER_INSERT_TEXT,
-	ROW_INSERTED,
 	LAST_EXTERNAL_SIGNAL
 };
 
@@ -120,7 +119,6 @@ struct _GtkSourceCompletionPrivate
 	gchar *filter_criteria;
 	
 	gboolean inserting_data;
-	
 	gulong signals_ids[LAST_EXTERNAL_SIGNAL];
 };
 
@@ -1701,9 +1699,11 @@ on_row_inserted_cb (GtkTreeModel *tree_model,
 					      completion->priv->info_visible);
 	
 		g_signal_emit (completion, signals[SHOW], 0);
-		
-		g_signal_handler_disconnect (tree_model, completion->priv->signals_ids[ROW_INSERTED]);
 	}
+	
+	gtk_tree_view_scroll_to_point (GTK_TREE_VIEW (completion->priv->tree_view_proposals),
+	                               0,
+	                               0);
 }
 
 static void
@@ -1741,6 +1741,11 @@ initialize_proposals_ui (GtkSourceCompletion *completion)
 				                      completion->priv->show_headers);
 	tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (completion->priv->model_proposals));
 	completion->priv->tree_view_proposals = tree_view;
+
+	g_signal_connect_after (completion->priv->model_proposals,
+	                        "row-inserted",
+	                        G_CALLBACK (on_row_inserted_cb),
+	                        completion);
 	
 	gtk_tree_view_set_show_expanders (GTK_TREE_VIEW (tree_view), FALSE);
 	
@@ -2029,12 +2034,6 @@ gtk_source_completion_show (GtkSourceCompletion *completion,
 	completion->priv->active_providers = 
 		g_list_reverse (completion->priv->active_providers);
 	
-	completion->priv->signals_ids[ROW_INSERTED] = 
-		g_signal_connect (completion->priv->model_proposals,
-				  "row-inserted",
-				  G_CALLBACK (on_row_inserted_cb),
-				  completion);
-	
 	return TRUE;
 }
 
diff --git a/gtksourceview/gtksourcecompletionmodel.c b/gtksourceview/gtksourcecompletionmodel.c
index 9c68c31..284d56a 100644
--- a/gtksourceview/gtksourcecompletionmodel.c
+++ b/gtksourceview/gtksourcecompletionmodel.c
@@ -23,6 +23,7 @@
 #include "gtksourcecompletionmodel.h"
 
 #define ITEMS_PER_CALLBACK 500
+#define FILTER_PER_CALLBACK 1000
 
 #define GTK_SOURCE_COMPLETION_MODEL_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), GTK_TYPE_SOURCE_COMPLETION_MODEL, GtkSourceCompletionModelPrivate))
 
@@ -60,12 +61,18 @@ struct _GtkSourceCompletionModelPrivate
 	
 	guint idle_id;
 	GQueue *item_queue;
+	
+	guint idle_filter_id;
+
+	GList *next_filter_item;
+	GtkTreeRowReference *next_filter_path;
 };
 
 /* Signals */
 enum
 {
 	ITEMS_ADDED,
+	FILTER_DONE,
 	LAST_SIGNAL
 };
 
@@ -441,35 +448,67 @@ free_node (ProposalNode *node)
 }
 
 static void
-gtk_source_completion_model_dispose (GObject *object)
+cancel_append (GtkSourceCompletionModel *model)
 {
-	GtkSourceCompletionModel *model = GTK_SOURCE_COMPLETION_MODEL (object);
-	
+	if (model->priv->item_queue != NULL)
+	{
+		g_queue_foreach (model->priv->item_queue,
+				 (GFunc)free_node, NULL);
+		g_queue_clear (model->priv->item_queue);
+	}
+
 	if (model->priv->idle_id != 0)
 	{
 		g_source_remove (model->priv->idle_id);
 		model->priv->idle_id = 0;
+	}	
+}
+
+static void
+cancel_refilter (GtkSourceCompletionModel *model)
+{
+	if (model->priv->next_filter_path != NULL)
+	{
+		gtk_tree_row_reference_free (model->priv->next_filter_path);
+		model->priv->next_filter_path = NULL;
 	}
 	
-	if (model->priv->item_queue != NULL)
+	if (model->priv->idle_filter_id != 0)
 	{
-		g_queue_foreach (model->priv->item_queue,
-				 (GFunc)free_node, NULL);
-		g_queue_free (model->priv->item_queue);
+		g_source_remove (model->priv->idle_filter_id);
+		model->priv->idle_filter_id = 0;
 		
-		model->priv->item_queue = NULL;
+		g_signal_emit (model, signals[FILTER_DONE], 0);
 	}
-
-	G_OBJECT_CLASS (gtk_source_completion_model_parent_class)->dispose (object);
 }
 
 static void
-gtk_source_completion_model_finalize (GObject *object)
+gtk_source_completion_model_dispose (GObject *object)
 {
 	GtkSourceCompletionModel *model = GTK_SOURCE_COMPLETION_MODEL (object);
+
+	cancel_append (model);
+	cancel_refilter (model);
+	
+	g_queue_free (model->priv->item_queue);
+	model->priv->item_queue = NULL;
+	
+	if (model->priv->num_per_provider != NULL)
+	{
+		g_hash_table_destroy (model->priv->num_per_provider);
+		model->priv->num_per_provider = NULL;
+	}
 	
-	g_hash_table_destroy (model->priv->num_per_provider);
+	g_list_foreach (model->priv->store, (GFunc)free_node, NULL);
+	g_list_free (model->priv->store);
+	model->priv->store = NULL;
 
+	G_OBJECT_CLASS (gtk_source_completion_model_parent_class)->dispose (object);
+}
+
+static void
+gtk_source_completion_model_finalize (GObject *object)
+{
 	G_OBJECT_CLASS (gtk_source_completion_model_parent_class)->finalize (object);
 }
 
@@ -493,6 +532,18 @@ gtk_source_completion_model_class_init (GtkSourceCompletionModelClass *klass)
 			      g_cclosure_marshal_VOID__VOID, 
 			      G_TYPE_NONE,
 			      0);
+
+	signals[FILTER_DONE] =
+		g_signal_new ("filter-done",
+			      G_TYPE_FROM_CLASS (klass),
+			      G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+			      G_STRUCT_OFFSET (GtkSourceCompletionModelClass, filter_done),
+			      NULL, 
+			      NULL,
+			      g_cclosure_marshal_VOID__VOID, 
+			      G_TYPE_NONE,
+			      0);
+
 }
 
 static void
@@ -879,10 +930,8 @@ gtk_source_completion_model_clear (GtkSourceCompletionModel *model)
 	g_return_if_fail (GTK_IS_SOURCE_COMPLETION_MODEL (model));
 	
 	/* Clear the queue of missing elements to append */
-	g_queue_foreach (model->priv->item_queue,
-			 (GFunc)free_node, NULL);
-	g_queue_clear (model->priv->item_queue);
-	model->priv->idle_id = 0;
+	cancel_append (model);
+	cancel_refilter (model);
 	
 	path = gtk_tree_path_new_first ();
 	list = model->priv->store;
@@ -918,24 +967,31 @@ gtk_source_completion_model_clear (GtkSourceCompletionModel *model)
 	g_hash_table_remove_all (model->priv->num_per_provider);
 }
 
-void
-gtk_source_completion_model_refilter (GtkSourceCompletionModel *model)
+static gboolean
+idle_refilter (GtkSourceCompletionModel *model)
 {
-	GList *item;
-	GtkSourceCompletionModelFilterFlag filtered;
-	ProposalNode *node;
+	guint i = 0;
 	GtkTreePath *path;
 	GtkTreeIter iter;
+	ProposalNode *node;
+	GtkSourceCompletionModelFilterFlag filtered;
 
-	g_return_if_fail (GTK_IS_SOURCE_COMPLETION_MODEL (model));
-	
-	path = gtk_tree_path_new_first ();
+	if (model->priv->next_filter_path)
+	{
+		path = gtk_tree_row_reference_get_path (model->priv->next_filter_path);
+		gtk_tree_row_reference_free (model->priv->next_filter_path);
+		model->priv->next_filter_path = NULL;
+	}
+	else
+	{
+		path = gtk_tree_path_new_first ();
+	}
 	
-	for (item = model->priv->store; item != NULL; item = g_list_next (item))
+	while (i < FILTER_PER_CALLBACK && model->priv->next_filter_item != NULL)
 	{
-		iter.user_data = item;
+		iter.user_data = model->priv->next_filter_item;
 
-		node = (ProposalNode *)item->data;
+		node = (ProposalNode *)model->priv->next_filter_item->data;
 		filtered = node_update_filter_state (model, node);
 		
 		if ((filtered != 0) == (node->filtered != 0))
@@ -970,10 +1026,49 @@ gtk_source_completion_model_refilter (GtkSourceCompletionModel *model)
 			gtk_tree_model_row_deleted (GTK_TREE_MODEL (model),
 			                            path);
 		}
+		
+		model->priv->next_filter_item = g_list_next (model->priv->next_filter_item);
+		++i;
 	}
 
-	gtk_tree_path_free (path);
 	refilter_headers (model);
+
+	if (model->priv->next_filter_item == NULL)
+	{
+		model->priv->idle_filter_id = 0;
+		gtk_tree_path_free (path);
+		
+		g_signal_emit (model, signals[FILTER_DONE], 0);
+
+		return FALSE;
+	}
+	
+	if (gtk_tree_path_prev (path))
+	{
+		model->priv->next_filter_path = gtk_tree_row_reference_new (GTK_TREE_MODEL (model),
+		                                                            path);
+	}
+	
+	gtk_tree_path_free (path);
+
+	return TRUE;
+}
+
+void
+gtk_source_completion_model_refilter (GtkSourceCompletionModel *model)
+{
+	g_return_if_fail (GTK_IS_SOURCE_COMPLETION_MODEL (model));
+	
+	/* Cancel any running filter */
+	cancel_refilter (model);
+	
+	model->priv->next_filter_item = model->priv->store;
+	
+	if (idle_refilter (model))
+	{
+		model->priv->idle_filter_id = g_idle_add ((GSourceFunc)idle_refilter, 
+		                                          model);
+	}
 }
 
 gboolean
diff --git a/gtksourceview/gtksourcecompletionmodel.h b/gtksourceview/gtksourcecompletionmodel.h
index 5844b5c..b62b3f0 100644
--- a/gtksourceview/gtksourcecompletionmodel.h
+++ b/gtksourceview/gtksourcecompletionmodel.h
@@ -50,7 +50,8 @@ struct _GtkSourceCompletionModel {
 struct _GtkSourceCompletionModelClass {
 	GObjectClass parent_class;
 	
-	void	(*items_added)	(GtkSourceCompletionModel *model);
+	void	(*items_added)		(GtkSourceCompletionModel *model);
+	void	(*filter_done)		(GtkSourceCompletionModel *model);
 };
 
 typedef enum



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]