[gtksourceview/gtksourcecompletion] Revert previous commits that I commited by mistake.



commit b0e5df9e362a220c861ac39ff2dedf76b3a2f181
Author: Ignacio Casal Quinteiro <icq gnome org>
Date:   Tue Jun 23 11:46:20 2009 +0200

    Revert previous commits that I commited by mistake.

 docs/reference/tmpl/view.sgml               |    9 +
 gtksourceview/gtksourcecompletion.c         |  171 ++++++++--
 gtksourceview/gtksourcecompletion.h         |    1 +
 gtksourceview/gtksourcecompletionmodel.c    |  479 ++++++++++++++++++++-------
 gtksourceview/gtksourcecompletionmodel.h    |   15 +-
 gtksourceview/gtksourcecompletionproposal.c |   72 ----
 gtksourceview/gtksourcecompletionproposal.h |    8 -
 gtksourceview/gtksourceview.c               |    2 +-
 8 files changed, 539 insertions(+), 218 deletions(-)
---
diff --git a/docs/reference/tmpl/view.sgml b/docs/reference/tmpl/view.sgml
index c172bc9..f599bb8 100644
--- a/docs/reference/tmpl/view.sgml
+++ b/docs/reference/tmpl/view.sgml
@@ -448,3 +448,12 @@ a text view which syntax highlighting, undo/redo and text marks. Use a
 @Returns: 
 
 
+<!-- ##### FUNCTION gtk_source_view_show_completion ##### -->
+<para>
+
+</para>
+
+ view: 
+ proposals: 
+
+
diff --git a/gtksourceview/gtksourcecompletion.c b/gtksourceview/gtksourcecompletion.c
index b639c7e..f8cd7d2 100644
--- a/gtksourceview/gtksourcecompletion.c
+++ b/gtksourceview/gtksourcecompletion.c
@@ -107,11 +107,13 @@ struct _GtkSourceCompletionPrivate
 	
 	guint show_timed_out_id;
 	guint auto_complete_delay;
+	guint minimum_auto_complete_length;
 	
 	gint typing_line;
 	gint typing_line_offset;
 	
 	GtkSourceCompletionProvider *filter_provider;
+	gchar *filter_criteria;
 	
 	gboolean inserting_data;
 	gboolean is_interactive;
@@ -494,7 +496,7 @@ update_selection_label (GtkSourceCompletion *completion)
 	{
 		name = g_markup_escape_text (
 			gtk_source_completion_provider_get_name (completion->priv->filter_provider),
-								 -1);
+			-1);
 
 		gtk_image_set_from_pixbuf (GTK_IMAGE (completion->priv->selection_image),
                            (GdkPixbuf *)gtk_source_completion_provider_get_icon (completion->priv->filter_provider));
@@ -510,12 +512,28 @@ update_selection_label (GtkSourceCompletion *completion)
 	else
 	{
 		gtk_label_set_markup (GTK_LABEL (completion->priv->selection_label),
-		                      name);
+		                      name);		                    
 	}
 	
 	g_free (name);
 }
 
+static void
+do_refilter (GtkSourceCompletion *completion,
+             gboolean             hide_if_empty)
+{
+	gtk_source_completion_model_refilter (completion->priv->model_proposals);
+	
+	/* Check if there are any proposals left */
+	if (hide_if_empty && !completion->priv->inserting_data &&
+	    gtk_source_completion_model_is_empty (completion->priv->model_proposals, FALSE))
+	{
+		gtk_source_completion_hide (completion);
+	}
+	
+	update_selection_label (completion);
+}
+
 typedef GList * (*ListSelector)(GList *);
 
 static gboolean
@@ -547,7 +565,7 @@ select_provider (GtkSourceCompletion *completion,
 			completion->priv->filter_provider = NULL;
 			
 			update_selection_label (completion);
-			//do_refilter (completion, FALSE);
+			do_refilter (completion, FALSE);
 			
 			return TRUE;
 		}
@@ -615,7 +633,7 @@ select_provider (GtkSourceCompletion *completion,
 	}
 	
 	update_selection_label (completion);
-	//do_refilter (completion, FALSE);
+	do_refilter (completion, FALSE);	
 	
 	return TRUE;
 }
@@ -675,6 +693,51 @@ update_info_position (GtkSourceCompletion *completion)
 	gtk_window_move (GTK_WINDOW (completion->priv->info_window), x, y);
 }
 
+static GtkSourceCompletionModelFilterFlag
+proposals_filter_func (GtkSourceCompletionModel    *model,
+                       GtkSourceCompletionProvider *provider,
+                       GtkSourceCompletionProposal *proposal,
+                       GtkSourceCompletion         *completion)
+{
+	GtkSourceCompletionModelFilterFlag ret = GTK_SOURCE_COMPLETION_MODEL_NONE;
+	gboolean visible;
+	gboolean count;
+	GtkTextIter iter;
+	
+	/* Filter on provider */
+	if (completion->priv->filter_provider != NULL && completion->priv->filter_provider != provider)
+	{
+		visible = FALSE;
+		count = TRUE;
+	}
+	else if (completion->priv->filter_criteria == NULL)
+	{
+		visible = TRUE;
+		count = FALSE;
+	}
+	else
+	{
+		visible = gtk_source_completion_provider_filter_proposal (provider,
+	                                                                  proposal,
+	                                                                  &iter,
+	                                                                  completion->priv->filter_criteria);
+
+		count = FALSE;
+	}
+	
+	if (!visible)
+	{
+		ret |= GTK_SOURCE_COMPLETION_MODEL_FILTERED;
+		
+		if (count)
+		{
+			ret |= GTK_SOURCE_COMPLETION_MODEL_COUNT;
+		}
+	}
+	
+	return ret;
+}
+
 static void
 row_activated_cb (GtkTreeView         *tree_view,
 		  GtkTreePath         *path,
@@ -975,6 +1038,20 @@ view_key_press_event_cb (GtkSourceView       *view,
 }
 
 static void
+refilter_proposals_with_word (GtkSourceCompletion *completion)
+{
+	GtkTextView *view;
+	
+	g_free (completion->priv->filter_criteria);
+	view = GTK_TEXT_VIEW (completion->priv->view);
+	
+	completion->priv->filter_criteria = 
+		gtk_source_completion_utils_get_word (GTK_SOURCE_BUFFER (gtk_text_view_get_buffer (view)));
+	
+	do_refilter (completion, TRUE);
+}
+
+static void
 update_typing_offsets (GtkSourceCompletion *completion)
 {
 	GtkTextBuffer *buffer;
@@ -1029,9 +1106,10 @@ show_auto_completion (GtkSourceCompletion *completion)
 							  &end);
 	
 	/* Check minimum amount of characters */
-	if (g_utf8_strlen (word, -1) >= 1)
+	if (g_utf8_strlen (word, -1) >= completion->priv->minimum_auto_complete_length)
 	{
-		gtk_source_completion_show (completion, providers, &start);
+		gtk_source_completion_show (completion, providers,
+					    word, &start);
 		completion->priv->is_interactive = TRUE;
 	}
 
@@ -1071,14 +1149,14 @@ buffer_delete_range_cb (GtkTextBuffer       *buffer,
 	{
 		if (gtk_text_iter_get_line (start) != completion->priv->typing_line ||
 		    (completion->priv->is_interactive && 
-		     gtk_text_iter_get_line_offset (start) < completion->priv->typing_line_offset + 1))
+		     gtk_text_iter_get_line_offset (start) < completion->priv->typing_line_offset +
+		     completion->priv->minimum_auto_complete_length))
 		{
 			gtk_source_completion_hide (completion);
 		}
 		else
 		{
-			//FIXME create the context, remove items, and add new ones
-			//refilter_proposals_with_word (completion);
+			refilter_proposals_with_word (completion);
 		}
 	}
 	
@@ -1105,16 +1183,15 @@ buffer_insert_text_cb (GtkTextBuffer       *buffer,
 	}
 	else
 	{
-		if ((completion->priv->is_interactive &&
-		    g_unichar_isspace (g_utf8_get_char (text))) ||
+		if ((completion->priv->is_interactive && 
+		     gtk_source_completion_utils_is_separator (g_utf8_get_char (text))) ||
 		    gtk_text_iter_get_line (location) != completion->priv->typing_line)
 		{
 			gtk_source_completion_hide (completion);
 		}
 		else
 		{
-			//FIXME create the context, remove items, and add new ones
-			//refilter_proposals_with_word (completion);
+			refilter_proposals_with_word (completion);
 		}
 	}
 }
@@ -1211,6 +1288,8 @@ gtk_source_completion_finalize (GObject *object)
 	g_hash_table_destroy (completion->priv->capability_map);
 	g_list_free (completion->priv->providers);
 	
+	g_free (completion->priv->filter_criteria);
+	
 	G_OBJECT_CLASS (gtk_source_completion_parent_class)->finalize (object);
 }
 
@@ -1246,6 +1325,9 @@ gtk_source_completion_get_property (GObject    *object,
 		case PROP_AUTO_COMPLETE_DELAY:
 			g_value_set_uint (value, completion->priv->auto_complete_delay);
 			break;
+		case PROP_MINIMUM_AUTO_COMPLETE_LENGTH:
+			g_value_set_uint (value, completion->priv->minimum_auto_complete_length);
+			break;
 		default:
 			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 			break;
@@ -1292,6 +1374,9 @@ gtk_source_completion_set_property (GObject      *object,
 		case PROP_AUTO_COMPLETE_DELAY:
 			completion->priv->auto_complete_delay = g_value_get_uint (value);
 			break;
+		case PROP_MINIMUM_AUTO_COMPLETE_LENGTH:
+			completion->priv->minimum_auto_complete_length = g_value_get_uint (value);
+			break;
 		default:
 			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 			break;
@@ -1301,9 +1386,6 @@ gtk_source_completion_set_property (GObject      *object,
 static void
 gtk_source_completion_hide_default (GtkSourceCompletion *completion)
 {
-	gtk_widget_hide (completion->priv->info_window);
-	gtk_widget_hide (completion->priv->window);
-
 	completion->priv->filter_provider = NULL;
 
 	gtk_label_set_markup (GTK_LABEL (completion->priv->default_info), "");
@@ -1313,7 +1395,13 @@ gtk_source_completion_hide_default (GtkSourceCompletion *completion)
 	g_list_free (completion->priv->active_providers);
 	completion->priv->active_providers = NULL;
 	
+	g_free (completion->priv->filter_criteria);
+	completion->priv->filter_criteria = NULL;
+	
 	completion->priv->info_visible = GTK_WIDGET_VISIBLE (completion->priv->info_window);
+	
+	gtk_widget_hide (completion->priv->info_window);
+	gtk_widget_hide (completion->priv->window);
 }
 
 static void
@@ -1432,6 +1520,21 @@ gtk_source_completion_class_init (GtkSourceCompletionClass *klass)
 							    G_MAXUINT,
 							    250,
 							    G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+	/**
+	 * GtkSourceCompletion:min-len:
+	 *
+	 * The minimum word length to initiate interactive completion.
+	 *
+	 */
+	g_object_class_install_property (object_class,
+					 PROP_MINIMUM_AUTO_COMPLETE_LENGTH,
+					 g_param_spec_uint ("minimum-auto-complete-length",
+							    _("Minimum Auto Complete Length"),
+							    _("Minimum word length to initiate interactive completion"),
+							    0,
+							    G_MAXUINT,
+							    3,
+							    G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
 
 	/**
 	 * GtkSourceCompletion::show:
@@ -1632,11 +1735,9 @@ on_row_inserted_cb (GtkTreeModel *tree_model,
 		g_signal_emit (completion, signals[SHOW], 0);
 	}
 	
-	/* FIXME this fixes the header visibility but produces the problem of
-	* scrolling */
-	/*gtk_tree_view_scroll_to_point (GTK_TREE_VIEW (completion->priv->tree_view_proposals),
+	gtk_tree_view_scroll_to_point (GTK_TREE_VIEW (completion->priv->tree_view_proposals),
 	                               0,
-	                               0);*/
+	                               0);
 }
 
 static void
@@ -1652,6 +1753,17 @@ on_items_added_cb (GtkSourceCompletionModel *model,
 	}
 }
 
+static void
+on_filter_done_cb (GtkSourceCompletionModel *model,
+		   GtkSourceCompletion      *completion)
+{
+	/* Check if there are any completions */
+	if (gtk_source_completion_model_is_empty (model, FALSE))
+	{
+		gtk_source_completion_hide (completion);
+	}
+}
+
 static GtkWidget *
 initialize_proposals_ui (GtkSourceCompletion *completion)
 {
@@ -1661,13 +1773,20 @@ initialize_proposals_ui (GtkSourceCompletion *completion)
 	GtkWidget *scrolled_window;
 	GtkWidget *tree_view;
 	
-	completion->priv->model_proposals = gtk_source_completion_model_new ();
+	completion->priv->model_proposals = 
+		gtk_source_completion_model_new ((GtkSourceCompletionModelVisibleFunc)proposals_filter_func, 
+		                                 completion);
 	
 	g_signal_connect (completion->priv->model_proposals,
 			  "items-added",
 			  G_CALLBACK (on_items_added_cb),
 			  completion);
 
+	g_signal_connect (completion->priv->model_proposals,
+			  "filter-done",
+			  G_CALLBACK (on_filter_done_cb),
+			  completion);
+
 	gtk_source_completion_model_set_show_headers (completion->priv->model_proposals,
 				                      completion->priv->show_headers);
 	tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (completion->priv->model_proposals));
@@ -1883,6 +2002,7 @@ gtk_source_completion_init (GtkSourceCompletion *completion)
 	                                                          g_str_equal,
 	                                                          (GDestroyNotify)g_free,
 	                                                          (GDestroyNotify)g_list_free);
+	                                                     
 
 	initialize_ui (completion);
 }
@@ -1915,7 +2035,7 @@ add_proposals (GtkSourceCompletion         *completion,
 	}
 
 	gtk_source_completion_model_run_add_proposals (completion->priv->model_proposals);
-
+	
 	g_list_free (proposals);
 }
 
@@ -1991,6 +2111,7 @@ remove_capabilities (GtkSourceCompletion          *completion,
  * gtk_source_completion_show:
  * @completion: A #GtkSourceCompletion
  * @providers: A list of #GtkSourceCompletionProvider
+ * @criteria: The filter criteria
  * @place: The place where you want to position the popup window, or %NULL
  *
  * Shows the show completion window. If @place if %NULL the popup window will
@@ -2001,6 +2122,7 @@ remove_capabilities (GtkSourceCompletion          *completion,
 gboolean
 gtk_source_completion_show (GtkSourceCompletion *completion,
                             GList               *providers,
+                            const gchar         *criteria,
                             GtkTextIter         *place)
 {
 	GList *l;
@@ -2016,6 +2138,7 @@ gtk_source_completion_show (GtkSourceCompletion *completion,
 		return FALSE;
 	}
 	
+	completion->priv->filter_criteria = g_strdup (criteria);
 	update_typing_offsets (completion);
 
 	if (place == NULL)
@@ -2043,11 +2166,11 @@ gtk_source_completion_show (GtkSourceCompletion *completion,
 			add_proposals (completion, GTK_SOURCE_COMPLETION_PROVIDER (l->data));
 		}
 	}
-
+		
 	completion->priv->active_providers = 
 		g_list_reverse (completion->priv->active_providers);
 
-	completion->priv->is_interactive = FALSE;
+	completion->priv->is_interactive = FALSE;		
 
 	update_selection_label (completion);
 	
diff --git a/gtksourceview/gtksourcecompletion.h b/gtksourceview/gtksourcecompletion.h
index bd439c4..8c3b638 100644
--- a/gtksourceview/gtksourcecompletion.h
+++ b/gtksourceview/gtksourcecompletion.h
@@ -88,6 +88,7 @@ GList		*gtk_source_completion_get_providers		(GtkSourceCompletion         *compl
                                                                  const gchar                 *capabilities);
 gboolean	 gtk_source_completion_show			(GtkSourceCompletion         *completion,
 								 GList                       *providers,
+								 const gchar                 *criteria,
 								 GtkTextIter                 *place);
 
 void		 gtk_source_completion_hide			(GtkSourceCompletion         *completion);
diff --git a/gtksourceview/gtksourcecompletionmodel.c b/gtksourceview/gtksourcecompletionmodel.c
index de4e9cd..4c90768 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))
 
@@ -33,14 +34,15 @@ typedef struct
 	GtkSourceCompletionProvider *provider;
 	GtkSourceCompletionProposal *proposal;
 	
+	GtkSourceCompletionModelFilterFlag filtered;
 	gulong changed_id;
 } ProposalNode;
 
 typedef struct
 {
 	GList *item;
-	GHashTable *hash;
 	guint num;
+	guint visible_items;
 } HeaderInfo;
 
 struct _GtkSourceCompletionModelPrivate
@@ -52,16 +54,25 @@ struct _GtkSourceCompletionModelPrivate
 	guint num;
 	GHashTable *num_per_provider;
 	
+	GtkSourceCompletionModelVisibleFunc filter;
+	gpointer filter_data;
+	
 	gboolean show_headers;
 	
 	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
 };
 
@@ -88,10 +99,22 @@ path_from_list (GtkSourceCompletionModel *model,
                 GList                    *item)
 {
 	gint index = 0;
+	GList *ptr = model->priv->store;
+	ProposalNode *node;
 	
-	index = g_list_position (model->priv->store, item);
+	while (ptr && ptr != item)
+	{
+		node = (ProposalNode *)ptr->data;
+		
+		if (!node->filtered)
+		{
+			++index;
+		}
+		
+		ptr = g_list_next (ptr);
+	}
 	
-	if (index == -1)
+	if (ptr != item)
 	{
 		return NULL;
 	}
@@ -133,6 +156,7 @@ get_iter_from_index (GtkSourceCompletionModel *model,
                      gint                      index)
 {
 	GList *item;
+	ProposalNode *node;
 
 	if (index < 0 || index >= model->priv->num)
 	{
@@ -141,7 +165,20 @@ get_iter_from_index (GtkSourceCompletionModel *model,
 	
 	item = model->priv->store;
 	
-	item = g_list_nth (item, index);
+	while (item != NULL && index >= 0)
+	{
+		node = (ProposalNode *)item->data;
+		
+		if (!node->filtered)
+		{
+			--index;
+		}
+
+		if (index != -1)
+		{
+			item = g_list_next (item);
+		}
+	}
 	
 	if (item != NULL)
 	{
@@ -236,16 +273,21 @@ tree_model_get_value (GtkTreeModel *tree_model,
 }
 
 static gboolean
-get_next_element (GList *item,
-		  GtkTreeIter *iter)
+find_first_not_filtered (GList       *item,
+                         GtkTreeIter *iter)
 {
-	while ((item = g_list_next (item)))
+	ProposalNode *node;
+
+	while (item)
 	{
-		ProposalNode *node = (ProposalNode *)item->data;
+		node = (ProposalNode *)item->data;
 		
-		/* Skip headers */
-		if (node->proposal != NULL)
+		if (!node->filtered)
+		{
 			break;
+		}
+		
+		item = g_list_next (item);
 	}
 	
 	if (item != NULL)
@@ -263,10 +305,14 @@ static gboolean
 tree_model_iter_next (GtkTreeModel *tree_model,
 		      GtkTreeIter  *iter)
 {
+	GList *item;
+	
 	g_return_val_if_fail (GTK_IS_SOURCE_COMPLETION_MODEL (tree_model), FALSE);
 	g_return_val_if_fail (iter != NULL, FALSE);
 	
-	return get_next_element ((GList *)iter->user_data, iter);
+	item = g_list_next ((GList *)iter->user_data);
+	
+	return find_first_not_filtered (item, iter);
 }
 
 static gboolean
@@ -278,9 +324,14 @@ tree_model_iter_children (GtkTreeModel *tree_model,
 	g_return_val_if_fail (iter != NULL, FALSE);
 	g_return_val_if_fail (parent == NULL || parent->user_data != NULL, FALSE);
 	
-	/* FIXME: not sure if this should be: (GList *)iter->user_data, iter */
-	//return get_next_element (GTK_SOURCE_COMPLETION_MODEL (tree_model)->priv->store, iter);
-	return get_next_element ((GList *)iter->user_data, iter);
+	if (parent != NULL)
+	{
+		return FALSE;
+	}
+	else
+	{
+		return find_first_not_filtered (GTK_SOURCE_COMPLETION_MODEL (tree_model)->priv->store, iter);
+	}
 }
 
 static gboolean
@@ -327,7 +378,7 @@ tree_model_iter_nth_child (GtkTreeModel *tree_model,
 	else
 	{
 		return get_iter_from_index (GTK_SOURCE_COMPLETION_MODEL (tree_model), 
-		                            iter,
+		                            iter, 
 		                            n);
 	}
 }
@@ -413,6 +464,24 @@ cancel_append (GtkSourceCompletionModel *model)
 	{
 		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->idle_filter_id != 0)
+	{
+		g_source_remove (model->priv->idle_filter_id);
+		model->priv->idle_filter_id = 0;
+		
+		g_signal_emit (model, signals[FILTER_DONE], 0);
 	}
 }
 
@@ -422,6 +491,7 @@ gtk_source_completion_model_dispose (GObject *object)
 	GtkSourceCompletionModel *model = GTK_SOURCE_COMPLETION_MODEL (object);
 
 	cancel_append (model);
+	cancel_refilter (model);
 	
 	if (model->priv->item_queue != NULL)
 	{
@@ -468,35 +538,26 @@ 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
 free_num (gpointer data)
 {
-	HeaderInfo *info = (HeaderInfo *)data;
-
-	g_hash_table_destroy (info->hash);
 	g_slice_free (HeaderInfo, data);
 }
 
-static gboolean
-compare_nodes (gconstpointer a,
-	       gconstpointer b)
-{
-	ProposalNode *p1 = (ProposalNode *)a;
-	ProposalNode *p2 = (ProposalNode *)b;
-	
-	return gtk_source_completion_proposal_equals (p1->proposal, p2->proposal);
-}
-
-static guint
-hash_node (gconstpointer v)
-{
-	ProposalNode *node = (ProposalNode *)v;
-	
-	return gtk_source_completion_proposal_get_hash (node->proposal);
-}
-
 static void
 gtk_source_completion_model_init (GtkSourceCompletionModel *self)
 {
@@ -519,39 +580,78 @@ gtk_source_completion_model_init (GtkSourceCompletionModel *self)
 }
 
 static void
-num_inc (GtkSourceCompletionModel    *model,
-         GtkSourceCompletionProvider *provider,
-         gboolean                     header)
+num_inc (GtkSourceCompletionModel           *model,
+         GtkSourceCompletionProvider        *provider,
+         gboolean                            inc_local,
+         gboolean                            inc_global)
 {
 	HeaderInfo *info;
 	
 	info = g_hash_table_lookup (model->priv->num_per_provider, provider);
 	
-	++model->priv->num;
+	if (inc_global)
+	{
+		++model->priv->num;
+		
+		if (info != NULL)
+		{
+			++info->visible_items;
+		}
+	}
 	
-	if (info != NULL && !header)
+	if (inc_local && info != NULL)
 	{
 		++(info->num);
 	}
 }
 
 static void
-num_dec (GtkSourceCompletionModel    *model,
-         GtkSourceCompletionProvider *provider,
-         gboolean                     header)
+num_dec (GtkSourceCompletionModel           *model,
+         GtkSourceCompletionProvider        *provider,
+         gboolean                            dec_local,
+         gboolean                            dec_global)
 {
 	HeaderInfo *info;
 	
 	info = g_hash_table_lookup (model->priv->num_per_provider, provider);
 	
-	--model->priv->num;
+	if (dec_global)
+	{
+		--model->priv->num;
 		
-	if (info != NULL && !header)
+		if (info != NULL)
+		{
+			--info->visible_items;
+		}
+	}
+
+	if (dec_local && info != NULL && info->num > 0)
 	{
 		--(info->num);
 	}
 }
 
+static GtkSourceCompletionModelFilterFlag
+node_update_filter_state (GtkSourceCompletionModel *model, 
+                          ProposalNode             *node)
+{
+	GtkSourceCompletionModelFilterFlag ret;
+	
+	if (node->proposal == NULL)
+	{
+		return node->filtered;
+	}
+	
+	ret = node->filtered;
+	
+	node->filtered = model->priv->filter (model, 
+	                                      node->provider, 
+	                                      node->proposal, 
+	                                      model->priv->filter_data);
+
+	return ret;
+}
+
 static void
 update_show_headers (GtkSourceCompletionModel *model,
                      gboolean                  show)
@@ -577,12 +677,20 @@ update_show_headers (GtkSourceCompletionModel *model,
 	
 	while (g_hash_table_iter_next (&hiter, (gpointer *)&provider, (gpointer *)&info))
 	{
-		if (info->num > 0)
+		if (info->visible_items > 0)
 		{
 			node = (ProposalNode *)info->item->data;
 			++num;
 			
-			items = g_list_append (items, info);
+			if (show && node->filtered)
+			{
+				items = g_list_append (items, info);
+			}
+			
+			if (!show && !node->filtered)
+			{
+				items = g_list_append (items, info);
+			}
 		}
 	}
 
@@ -593,9 +701,10 @@ update_show_headers (GtkSourceCompletionModel *model,
 			info = (HeaderInfo *)item->data;
 			node = (ProposalNode *)info->item->data;
 			
+			node->filtered = GTK_SOURCE_COMPLETION_MODEL_NONE;
 			iter.user_data = info->item;
 			
-			num_inc (model, node->provider, TRUE);
+			num_inc (model, node->provider, FALSE, TRUE);
 
 			path = path_from_list (model, info->item);
 			gtk_tree_model_row_inserted (GTK_TREE_MODEL (model),
@@ -610,8 +719,9 @@ update_show_headers (GtkSourceCompletionModel *model,
 		info = (HeaderInfo *)items->data;
 		node = (ProposalNode *)info->item->data;
 		
-		num_dec (model, node->provider, TRUE);
+		num_dec (model, node->provider, FALSE, TRUE);
 
+		node->filtered = GTK_SOURCE_COMPLETION_MODEL_FILTERED;
 		path = path_from_list (model, info->item);
 		gtk_tree_model_row_deleted (GTK_TREE_MODEL (model), path);
 		gtk_tree_path_free (path);
@@ -620,52 +730,71 @@ update_show_headers (GtkSourceCompletionModel *model,
 	g_list_free (items);
 }
 
+static void
+refilter_headers (GtkSourceCompletionModel *model)
+{
+	GtkSourceCompletionProvider *provider;
+	HeaderInfo *info;
+	GHashTableIter hiter;
+	ProposalNode *node;
+	GtkTreePath *path;
+
+	g_hash_table_iter_init (&hiter, model->priv->num_per_provider);
+	
+	while (g_hash_table_iter_next (&hiter, (gpointer *)&provider, (gpointer *)&info))
+	{
+		node = (ProposalNode *)info->item->data;
+		
+		if (!node->filtered)
+		{
+			node->filtered = GTK_SOURCE_COMPLETION_MODEL_FILTERED;
+			num_dec (model, provider, FALSE, TRUE);
+			
+			path = path_from_list (model, info->item);
+			gtk_tree_model_row_deleted (GTK_TREE_MODEL (model),
+			                            path);
+			gtk_tree_path_free (path);
+		}
+	}
+
+	if (model->priv->show_headers)
+	{
+		update_show_headers (model, TRUE);
+		return;
+	}
+}
+
 /* Public */
 GtkSourceCompletionModel*
-gtk_source_completion_model_new (void)
+gtk_source_completion_model_new (GtkSourceCompletionModelVisibleFunc func,
+                                 gpointer                            userdata)
 {
-	return g_object_new (GTK_TYPE_SOURCE_COMPLETION_MODEL, NULL);
+	GtkSourceCompletionModel *model = g_object_new (GTK_TYPE_SOURCE_COMPLETION_MODEL, NULL);
+	
+	model->priv->filter = func;
+	model->priv->filter_data = userdata;
+
+	return model;
 }
 
-static GList *
+static void
 append_list (GtkSourceCompletionModel *model,
-             HeaderInfo               *info,
-             ProposalNode             *node,
-             gboolean                 *inserted)
+             ProposalNode             *node)
 {
-	GList *item = NULL;
+	GList *item;
 	
-	if (info)
-		item = g_hash_table_lookup (info->hash, node);
+	item = g_list_append (model->priv->last, node);
 	
-	if (item == NULL)
+	if (model->priv->store == NULL)
 	{
-		item = g_list_append (model->priv->last, node);
-		
-		if (model->priv->store == NULL)
-		{
-			model->priv->store = item;
-		}
-		else
-		{
-			item = item->next;
-		}
-		
-		if (info)
-			g_hash_table_insert (info->hash, node, item);
-		*inserted = TRUE;
+		model->priv->store = item;
 	}
 	else
 	{
-		/*g_hash_table_replace (model->priv->hash_store, node, item);
-		free_node (item->data);
-		item->data = node;*/
-		*inserted = FALSE;
+		item = item->next;
 	}
 	
 	model->priv->last = item;
-	
-	return item;
 }
 
 static void
@@ -676,13 +805,16 @@ on_proposal_changed (GtkSourceCompletionProposal *proposal,
 	ProposalNode *node = (ProposalNode *)item->data;
 	GtkTreePath *path;
 
-	iter.user_data = node;
-	path = path_from_list (node->model, item);
+	if (!node->filtered)
+	{
+		iter.user_data = node;
+		path = path_from_list (node->model, item);
 
-	gtk_tree_model_row_changed (GTK_TREE_MODEL (node->model),
-	                            path,
-	                            &iter);
-	gtk_tree_path_free (path);
+		gtk_tree_model_row_changed (GTK_TREE_MODEL (node->model),
+		                            path,
+		                            &iter);
+		gtk_tree_path_free (path);
+	}
 }
 
 static gboolean
@@ -699,7 +831,6 @@ idle_append (gpointer data)
 		ProposalNode *node = (ProposalNode *)g_queue_pop_head (model->priv->item_queue);
 		ProposalNode *header = NULL;
 		GtkTreeIter iter;
-		gboolean inserted;
 		
 		if (node == NULL)
 		{
@@ -712,49 +843,52 @@ idle_append (gpointer data)
 		}
 		
 		/* Check if it is a header */
-		info = g_hash_table_lookup (model->priv->num_per_provider, node->provider);
-		
-		if (info == NULL)
+		if (g_hash_table_lookup (model->priv->num_per_provider, node->provider) == NULL)
 		{
-			/*header = g_slice_new (ProposalNode);
+			header = g_slice_new (ProposalNode);
 			header->provider = g_object_ref (node->provider);
 			header->proposal = NULL;
+			header->filtered = GTK_SOURCE_COMPLETION_MODEL_FILTERED;
 			
-			append_list (model, NULL, header, &inserted);*/
+			append_list (model, header);
 			
 			info = g_slice_new (HeaderInfo);
 			info->item = model->priv->last;
 			info->num = 0;
-			info->hash = g_hash_table_new (hash_node,
-						       compare_nodes);
+			info->visible_items = 0;
 			
 			g_hash_table_insert (model->priv->num_per_provider, node->provider, info);
 		}
 		
-		item = append_list (model, info, node, &inserted);
+		node_update_filter_state (model, node);
 		
-		if (inserted)
-		{
-			iter.user_data = item;
+		append_list (model, node);
+		
+		item = model->priv->last;
+		iter.user_data = item;
 
-			num_inc (model, node->provider, FALSE);
+		num_inc (model, 
+			 node->provider, 
+			 !node->filtered || (node->filtered & GTK_SOURCE_COMPLETION_MODEL_COUNT),
+			 !node->filtered);
 
+		if (!node->filtered)
+		{
 			path = path_from_list (model, item);
 			gtk_tree_model_row_inserted (GTK_TREE_MODEL (model), path, &iter);
 			gtk_tree_path_free (path);
-		}
-		
-		if (header != NULL)
-		{
-			g_warning ("header");
-			update_show_headers (model, TRUE);
+			
+			if (header != NULL)
+			{
+				update_show_headers (model, TRUE);
+			}
 		}
 		
 		node->changed_id = g_signal_connect (node->proposal, 
 	                                             "changed", 
 	                                             G_CALLBACK (on_proposal_changed),
 	                                             item);
-	
+		
 		i++;
 	}
 	
@@ -798,11 +932,13 @@ gtk_source_completion_model_clear (GtkSourceCompletionModel *model)
 	GtkTreePath *path;
 	ProposalNode *node;
 	GList *list;
+	GtkSourceCompletionModelFilterFlag filtered;
 	
 	g_return_if_fail (GTK_IS_SOURCE_COMPLETION_MODEL (model));
 	
 	/* Clear the queue of missing elements to append */
 	cancel_append (model);
+	cancel_refilter (model);
 	
 	path = gtk_tree_path_new_first ();
 	list = model->priv->store;
@@ -810,8 +946,7 @@ gtk_source_completion_model_clear (GtkSourceCompletionModel *model)
 	while (model->priv->store)
 	{
 		node = (ProposalNode *)model->priv->store->data;
-
-		num_dec (model, node->provider, node->proposal == NULL);
+		filtered = node->filtered;
 
 		free_node (node);
 		
@@ -822,7 +957,15 @@ gtk_source_completion_model_clear (GtkSourceCompletionModel *model)
 			model->priv->last = NULL;
 		}
 		
-		gtk_tree_model_row_deleted (GTK_TREE_MODEL (model), path);
+		num_dec (model, 
+		         node->provider, 
+		         (!filtered || (filtered & GTK_SOURCE_COMPLETION_MODEL_COUNT)) && node->proposal != NULL,
+		         !filtered);
+		
+		if (!filtered)
+		{
+			gtk_tree_model_row_deleted (GTK_TREE_MODEL (model), path);
+		}
 	}
 	
 	g_list_free (list);
@@ -831,6 +974,110 @@ gtk_source_completion_model_clear (GtkSourceCompletionModel *model)
 	g_hash_table_remove_all (model->priv->num_per_provider);
 }
 
+static gboolean
+idle_refilter (GtkSourceCompletionModel *model)
+{
+	guint i = 0;
+	GtkTreePath *path;
+	GtkTreeIter iter;
+	ProposalNode *node;
+	GtkSourceCompletionModelFilterFlag filtered;
+
+	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 ();
+	}
+	
+	while (i < FILTER_PER_CALLBACK && model->priv->next_filter_item != NULL)
+	{
+		iter.user_data = model->priv->next_filter_item;
+
+		node = (ProposalNode *)model->priv->next_filter_item->data;
+		filtered = node_update_filter_state (model, node);
+		
+		if ((filtered != 0) == (node->filtered != 0))
+		{
+			/* Keep the same, so increase path */
+			if (!filtered)
+			{
+				gtk_tree_path_next (path);
+			}
+		}
+		else if (filtered)
+		{
+			/* Was filtered, but not any more, so insert it */
+			num_inc (model, 
+			         node->provider,
+			         !(filtered & GTK_SOURCE_COMPLETION_MODEL_COUNT),
+			         TRUE);
+			         
+			gtk_tree_model_row_inserted (GTK_TREE_MODEL (model),
+			                             path,
+			                             &iter);
+			gtk_tree_path_next (path);
+		}
+		else
+		{
+			/* Was not filtered, but is now, so remove it */
+			num_dec (model, 
+			         node->provider,
+			         !(node->filtered & GTK_SOURCE_COMPLETION_MODEL_COUNT),
+			         TRUE);
+
+			gtk_tree_model_row_deleted (GTK_TREE_MODEL (model),
+			                            path);
+		}
+		
+		model->priv->next_filter_item = g_list_next (model->priv->next_filter_item);
+		++i;
+	}
+
+	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
 gtk_source_completion_model_is_empty (GtkSourceCompletionModel *model,
                                       gboolean                  invisible)
@@ -878,7 +1125,7 @@ gtk_source_completion_model_set_show_headers (GtkSourceCompletionModel *model,
 	if (model->priv->show_headers != show_headers)
 	{
 		model->priv->show_headers = show_headers;
-		//update_show_headers (model, show_headers);
+		refilter_headers (model);
 	}
 }
 
@@ -905,7 +1152,11 @@ gtk_source_completion_model_iter_previous (GtkSourceCompletionModel *model,
 	
 	item = iter->user_data;
 	
-	item = g_list_previous (item);
+	do
+	{
+		item = g_list_previous (item);
+	} while (item && ((ProposalNode *)item->data)->filtered);
+
 	
 	if (item != NULL)
 	{
@@ -930,7 +1181,11 @@ gtk_source_completion_model_iter_last (GtkSourceCompletionModel *model,
 	item = model->priv->last;
 	iter->user_data = item;
 
-	if (item != NULL)
+	if (!((ProposalNode *)item->data)->filtered)
+	{
+		return TRUE;
+	}
+	else if (item != NULL)
 	{
 		return gtk_source_completion_model_iter_previous (model, iter);
 	}
diff --git a/gtksourceview/gtksourcecompletionmodel.h b/gtksourceview/gtksourcecompletionmodel.h
index 05c2039..bb112ae 100644
--- a/gtksourceview/gtksourcecompletionmodel.h
+++ b/gtksourceview/gtksourcecompletionmodel.h
@@ -54,6 +54,13 @@ struct _GtkSourceCompletionModelClass {
 	void	(*filter_done)		(GtkSourceCompletionModel *model);
 };
 
+typedef enum
+{
+	GTK_SOURCE_COMPLETION_MODEL_NONE,
+	GTK_SOURCE_COMPLETION_MODEL_FILTERED = 1 << 0,
+	GTK_SOURCE_COMPLETION_MODEL_COUNT = 1 << 1
+} GtkSourceCompletionModelFilterFlag;
+
 enum
 {
 	GTK_SOURCE_COMPLETION_MODEL_COLUMN_LABEL,
@@ -64,10 +71,16 @@ enum
 	GTK_SOURCE_COMPLETION_MODEL_N_COLUMNS
 };
 
+typedef GtkSourceCompletionModelFilterFlag (* GtkSourceCompletionModelVisibleFunc) (GtkSourceCompletionModel    *model,
+                                                          GtkSourceCompletionProvider *provider,
+                                                          GtkSourceCompletionProposal *proposal,
+                                                          gpointer                     userdata);
+
 GType gtk_source_completion_model_get_type (void) G_GNUC_CONST;
 
 GtkSourceCompletionModel *
-		gtk_source_completion_model_new 	(void);
+		gtk_source_completion_model_new 	(GtkSourceCompletionModelVisibleFunc func,
+							 gpointer                            userdata);
 
 void		gtk_source_completion_model_run_add_proposals (GtkSourceCompletionModel *model);
 
diff --git a/gtksourceview/gtksourcecompletionproposal.c b/gtksourceview/gtksourcecompletionproposal.c
index 2bfc8ee..fd1352e 100644
--- a/gtksourceview/gtksourcecompletionproposal.c
+++ b/gtksourceview/gtksourcecompletionproposal.c
@@ -74,59 +74,6 @@ gtk_source_completion_proposal_get_info_default (GtkSourceCompletionProposal *pr
 	return NULL;
 }
 
-static guint
-gtk_source_completion_proposal_get_hash_default (GtkSourceCompletionProposal *proposal)
-{
-	const gchar *label;
-	
-	label = gtk_source_completion_proposal_get_label (proposal);
-	
-	if (label == NULL)
-		label = gtk_source_completion_proposal_get_markup (proposal);
-	
-	if (label != NULL)
-		return g_str_hash (label);
-	else
-		g_return_val_if_reached (0);
-}
-
-static gboolean
-gtk_source_completion_proposal_equals_default (GtkSourceCompletionProposal *proposal1,
-					       GtkSourceCompletionProposal *proposal2)
-{
-	const gchar *label1, *label2;
-	
-	label1 = gtk_source_completion_proposal_get_markup (proposal1);
-	label2 = gtk_source_completion_proposal_get_markup (proposal2);
-
-	if (label1 != NULL && label2 == NULL)
-	{
-		return FALSE;
-	}
-	else if (label2 != NULL && label1 == NULL)
-	{
-		return FALSE;
-	}
-	else if (label1 == NULL && label2 == NULL)
-	{
-		label1 = gtk_source_completion_proposal_get_label (proposal1);
-		label2 = gtk_source_completion_proposal_get_label (proposal2);
-	}
-
-	if (label1 != NULL && label2 != NULL)
-	{
-		/* FIXME: g_utf8_collate ??? */
-		if (g_strcmp0 (label1, label2) == 0)
-			return TRUE;
-		else
-			return FALSE;
-	}
-	else
-	{
-		g_return_val_if_reached (FALSE);
-	}
-}
-
 static void 
 gtk_source_completion_proposal_init (GtkSourceCompletionProposalIface *iface)
 {
@@ -139,9 +86,6 @@ gtk_source_completion_proposal_init (GtkSourceCompletionProposalIface *iface)
 	iface->get_icon = gtk_source_completion_proposal_get_icon_default;
 	iface->get_info = gtk_source_completion_proposal_get_info_default;
 	
-	iface->get_hash = gtk_source_completion_proposal_get_hash_default;
-	iface->equals = gtk_source_completion_proposal_equals_default;
-	
 	if (!initialized)
 	{
 		/**
@@ -282,22 +226,6 @@ gtk_source_completion_proposal_get_info (GtkSourceCompletionProposal *proposal)
 	return GTK_SOURCE_COMPLETION_PROPOSAL_GET_INTERFACE (proposal)->get_info (proposal);
 }
 
-guint
-gtk_source_completion_proposal_get_hash (GtkSourceCompletionProposal *proposal)
-{
-	g_return_val_if_fail (GTK_IS_SOURCE_COMPLETION_PROPOSAL (proposal), 0);
-	return GTK_SOURCE_COMPLETION_PROPOSAL_GET_INTERFACE (proposal)->get_hash (proposal);
-}
-
-gboolean
-gtk_source_completion_proposal_equals (GtkSourceCompletionProposal *proposal1,
-				       GtkSourceCompletionProposal *proposal2)
-{
-	g_return_val_if_fail (GTK_IS_SOURCE_COMPLETION_PROPOSAL (proposal1), FALSE);
-	g_return_val_if_fail (GTK_IS_SOURCE_COMPLETION_PROPOSAL (proposal2), FALSE);
-	return GTK_SOURCE_COMPLETION_PROPOSAL_GET_INTERFACE (proposal1)->equals (proposal1, proposal2);
-}
-
 /**
  * gtk_source_completion_proposal_changed:
  * @proposal: A #GtkSourceCompletionProposal
diff --git a/gtksourceview/gtksourcecompletionproposal.h b/gtksourceview/gtksourcecompletionproposal.h
index 6ddcaa8..abb147a 100644
--- a/gtksourceview/gtksourcecompletionproposal.h
+++ b/gtksourceview/gtksourcecompletionproposal.h
@@ -49,10 +49,6 @@ struct _GtkSourceCompletionProposalIface
 	GdkPixbuf	*(*get_icon)	(GtkSourceCompletionProposal *proposal);
 	const gchar	*(*get_info)	(GtkSourceCompletionProposal *proposal);
 	
-	guint		 (*get_hash)	(GtkSourceCompletionProposal *proposal);
-	gboolean	 (*equals)	(GtkSourceCompletionProposal *proposal1,
-					 GtkSourceCompletionProposal *proposal2);
-	
 	/* Signals */
 	void		 (*changed)	(GtkSourceCompletionProposal *proposal);
 };
@@ -66,10 +62,6 @@ const gchar		*gtk_source_completion_proposal_get_text	(GtkSourceCompletionPropos
 GdkPixbuf		*gtk_source_completion_proposal_get_icon	(GtkSourceCompletionProposal *proposal);
 const gchar		*gtk_source_completion_proposal_get_info	(GtkSourceCompletionProposal *proposal);
 
-guint			 gtk_source_completion_proposal_get_hash	(GtkSourceCompletionProposal *proposal);
-gboolean		 gtk_source_completion_proposal_equals		(GtkSourceCompletionProposal *proposal1,
-									 GtkSourceCompletionProposal *proposal2);
-
 void			 gtk_source_completion_proposal_changed		(GtkSourceCompletionProposal *proposal);
 
 G_END_DECLS
diff --git a/gtksourceview/gtksourceview.c b/gtksourceview/gtksourceview.c
index 41fbbde..4dbb012 100644
--- a/gtksourceview/gtksourceview.c
+++ b/gtksourceview/gtksourceview.c
@@ -1021,7 +1021,7 @@ gtk_source_view_show_completion_real (GtkSourceView *view)
 	word = gtk_source_completion_utils_get_word (
 			GTK_SOURCE_BUFFER (gtk_text_view_get_buffer (GTK_TEXT_VIEW (view))));
 
-	gtk_source_completion_show (completion, providers, NULL);
+	gtk_source_completion_show (completion, providers, word, NULL);
 
 	g_free (word);
 	g_list_foreach (providers, (GFunc)g_object_unref, NULL);



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