gtksourceview r2276 - in branches/gtksourcecompletion: gtksourceview tests



Author: jessevdk
Date: Mon Apr 13 17:44:09 2009
New Revision: 2276
URL: http://svn.gnome.org/viewvc/gtksourceview?rev=2276&view=rev

Log:
Implemented custom tree model for storing the proposals, increases performance significantly.


Added:
   branches/gtksourcecompletion/gtksourceview/gtksourcecompletionmodel.c
   branches/gtksourcecompletion/gtksourceview/gtksourcecompletionmodel.h
Modified:
   branches/gtksourcecompletion/gtksourceview/Makefile.am
   branches/gtksourcecompletion/gtksourceview/gtksourcecompletion.c
   branches/gtksourcecompletion/gtksourceview/gtksourcecompletion.h
   branches/gtksourcecompletion/tests/completion-simple.c
   branches/gtksourcecompletion/tests/gsc-provider-test.c

Modified: branches/gtksourcecompletion/gtksourceview/Makefile.am
==============================================================================
--- branches/gtksourcecompletion/gtksourceview/Makefile.am	(original)
+++ branches/gtksourcecompletion/gtksourceview/Makefile.am	Mon Apr 13 17:44:09 2009
@@ -32,9 +32,11 @@
 	gtksourcecompletioninfo.h		\
 	gtksourcecompletionitem.h		\
 	gtksourcecompletionproposal.h		\
-	gtksourcecompletionprovider.h
+	gtksourcecompletionprovider.h		\
+	gtksourcecompletionmodel.h
 
 NOINST_H_FILES = \
+	gtksourcecompletionutils.h		\
 	gtksourcecompletion-private.h
 
 libgtksourceview_2_0_la_SOURCES = 	\
@@ -69,8 +71,8 @@
 	gtksourcecompletionitem.c	\
 	gtksourcecompletionproposal.c	\
 	gtksourcecompletionprovider.c	\
+	gtksourcecompletionmodel.c	\
 	gtksourcecompletionutils.c	\
-	gtksourcecompletionutils.h	\
 	$(libgtksourceview_headers)	\
 	$(NOINST_H_FILES)
 

Modified: branches/gtksourcecompletion/gtksourceview/gtksourcecompletion.c
==============================================================================
--- branches/gtksourcecompletion/gtksourceview/gtksourcecompletion.c	(original)
+++ branches/gtksourcecompletion/gtksourceview/gtksourcecompletion.c	Mon Apr 13 17:44:09 2009
@@ -33,6 +33,7 @@
 #include "gtksourceview-marshal.h"
 #include <gtksourceview/gtksourcecompletion.h>
 #include "gtksourceview-i18n.h"
+#include "gtksourcecompletionmodel.h"
 #include <string.h>
 #include <gtksourceview/gtksourceview.h>
 #include "gtksourcecompletion-private.h"
@@ -45,15 +46,6 @@
 						  GTK_TYPE_SOURCE_COMPLETION,           \
 						  GtkSourceCompletionPrivate))
 
-enum
-{
-	COLUMN_PIXBUF,
-	COLUMN_NAME,
-	COLUMN_PROPOSAL,
-	COLUMN_PROVIDER,
-	N_COLUMNS
-};
-
 /* Signals */
 enum
 {
@@ -93,8 +85,7 @@
 	GtkWidget *default_info;
 	
 	GtkWidget *tree_view_proposals;
-	GtkListStore *list_store_proposals;
-	GtkTreeModelFilter *model_filter_proposals;
+	GtkSourceCompletionModel *model_proposals;
 	
 	gboolean destroy_has_run;
 	gboolean manage_keys;
@@ -139,10 +130,10 @@
 	
 	if (gtk_tree_selection_get_selected (selection, NULL, &piter))
 	{
-		model = GTK_TREE_MODEL (completion->priv->model_filter_proposals);
+		model = GTK_TREE_MODEL (completion->priv->model_proposals);
 		
 		gtk_tree_model_get (model, &piter,
-				    COLUMN_PROPOSAL,
+				    GTK_SOURCE_COMPLETION_MODEL_COLUMN_PROPOSAL,
 				    proposal, -1);
 		
 		if (iter != NULL)
@@ -198,7 +189,7 @@
 		return FALSE;
 	}
 
-	model = GTK_TREE_MODEL (completion->priv->model_filter_proposals);
+	model = GTK_TREE_MODEL (completion->priv->model_proposals);
 	
 	hasselection = gtk_tree_selection_get_selected (selection, NULL, &iter);
 	
@@ -338,6 +329,20 @@
 	}
 }
 
+static void
+do_refilter (GtkSourceCompletion *completion,
+             gboolean             finish_if_empty)
+{
+	gtk_source_completion_model_refilter (completion->priv->model_proposals);
+	
+	/* Check if there are any proposals left */
+	if (finish_if_empty && 
+	    gtk_source_completion_model_is_empty (completion->priv->model_proposals))
+	{
+		gtk_source_completion_finish (completion);
+	}
+}
+
 typedef GList * (*ListSelector)(GList *);
 
 static gboolean
@@ -380,8 +385,8 @@
 		completion->priv->filter_provider = p1;
 	}
 	
-	update_selection_label (completion);	
-	gtk_tree_model_filter_refilter (completion->priv->model_filter_proposals);
+	update_selection_label (completion);
+	do_refilter (completion, FALSE);	
 	
 	return TRUE;
 }
@@ -441,24 +446,13 @@
 }
 
 static gboolean
-proposals_filter_func (GtkTreeModel        *model,
-                       GtkTreeIter         *iter,
-                       GtkSourceCompletion *completion)
+proposals_filter_func (GtkSourceCompletionModel    *model,
+                       GtkSourceCompletionProvider *provider,
+                       GtkSourceCompletionProposal *proposal,
+                       GtkSourceCompletion         *completion)
 {
-	GtkSourceCompletionProvider *provider;
-	GtkSourceCompletionProposal *proposal;
 	gboolean ret;
 	
-	gtk_tree_model_get (model, iter,
-	                    COLUMN_PROVIDER, &provider,
-	                    COLUMN_PROPOSAL, &proposal,
-	                    -1);
-	
-	if (provider == NULL)
-	{
-		return TRUE;
-	}
-	
 	/* Filter on provider */
 	if (completion->priv->filter_provider != NULL &&
 	    completion->priv->filter_provider != provider)
@@ -476,11 +470,7 @@
 	                                                              completion->priv->filter_criteria);
 	}
 	
-	g_object_unref (provider);
-	g_object_unref (proposal);
-	
 	return ret;
-
 }
 
 static void
@@ -535,8 +525,8 @@
 	
 	if (get_selected_proposal (completion, &iter, &proposal))
 	{
-		model = GTK_TREE_MODEL (completion->priv->model_filter_proposals);
-		gtk_tree_model_get (model, &iter, COLUMN_PROVIDER, &provider, -1);
+		model = GTK_TREE_MODEL (completion->priv->model_proposals);
+		gtk_tree_model_get (model, &iter, GTK_SOURCE_COMPLETION_MODEL_COLUMN_PROVIDER, &provider, -1);
 		
 		update_proposal_info_real (completion, provider, proposal);
 		
@@ -566,14 +556,10 @@
 {
 	GtkTreeIter iter;
 
-	gtk_list_store_append (completion->priv->list_store_proposals, &iter);
-	gtk_list_store_set (completion->priv->list_store_proposals, 
-			    &iter,
-			    COLUMN_PIXBUF, gtk_source_completion_proposal_get_icon (proposal),
-			    COLUMN_NAME, gtk_source_completion_proposal_get_label (proposal),
-			    COLUMN_PROPOSAL, proposal,
-			    COLUMN_PROVIDER, provider,
-			    -1);
+	gtk_source_completion_model_append (completion->priv->model_proposals,
+	                                    provider,
+	                                    proposal,
+	                                    &iter);
 }
 
 static void
@@ -663,7 +649,7 @@
 
 	gtk_label_set_markup (GTK_LABEL (completion->priv->default_info), "");
 
-	gtk_list_store_clear (completion->priv->list_store_proposals);
+	gtk_source_completion_model_clear (completion->priv->model_proposals);
 
 	g_list_free (completion->priv->active_providers);
 	completion->priv->active_providers = NULL;
@@ -814,6 +800,7 @@
 					!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (completion->priv->info_button)));
 				ret = TRUE;
 			}
+			break;
 		}
 		case GDK_Left:
 		{
@@ -845,8 +832,25 @@
 	
 	completion->priv->filter_criteria = 
 		gtk_source_completion_utils_get_word (GTK_SOURCE_BUFFER (gtk_text_view_get_buffer (view)));
+	
+	do_refilter (completion, TRUE);
+}
 
-	gtk_tree_model_filter_refilter (completion->priv->model_filter_proposals);
+static void
+update_typing_offsets (GtkSourceCompletion *completion)
+{
+	GtkTextBuffer *buffer;
+	GtkTextMark *mark;
+	GtkTextIter iter;
+
+	buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (completion->priv->view));
+	mark = gtk_text_buffer_get_insert (buffer);
+
+	/* Check if the user has changed the cursor position.If yes, we don't complete */
+	gtk_text_buffer_get_iter_at_mark (buffer, &iter, mark);
+
+	completion->priv->typing_line = gtk_text_iter_get_line (&iter);
+	completion->priv->typing_line_offset = gtk_text_iter_get_line_offset (&iter);
 }
 
 static gboolean
@@ -924,19 +928,21 @@
 	
 	if (!GTK_WIDGET_VISIBLE (completion))
 	{
-		completion->priv->typing_line = gtk_text_iter_get_line (location);
-		completion->priv->typing_line_offset = gtk_text_iter_get_line_offset (location);
-
-		if (completion->priv->show_timed_out_id != 0)
+		if (completion->priv->auto_providers != NULL)
 		{
-			g_source_remove (completion->priv->show_timed_out_id);
-			completion->priv->show_timed_out_id = 0;
-		}
+			update_typing_offsets (completion);
+		
+			if (completion->priv->show_timed_out_id != 0)
+			{
+				g_source_remove (completion->priv->show_timed_out_id);
+				completion->priv->show_timed_out_id = 0;
+			}
 
-		completion->priv->show_timed_out_id = 
-			g_timeout_add (completion->priv->auto_complete_delay,
-			               (GSourceFunc)show_auto_completion,
-			               completion);
+			completion->priv->show_timed_out_id = 
+				g_timeout_add (completion->priv->auto_complete_delay,
+					       (GSourceFunc)show_auto_completion,
+					       completion);
+		}
 	}
 	else
 	{
@@ -1265,26 +1271,15 @@
 {
 	GtkCellRenderer *renderer;
 	GtkTreeViewColumn *column;
-	GtkTreeModel *model;
 	GtkTreeSelection *selection;
 	GtkWidget *scrolled_window;
 	GtkWidget *tree_view;
 	
-	completion->priv->list_store_proposals = gtk_list_store_new (N_COLUMNS,
-					                             GDK_TYPE_PIXBUF, 
-					                             G_TYPE_STRING, 
-					                             G_TYPE_OBJECT, 
-					                             G_TYPE_OBJECT);
-
-	model = gtk_tree_model_filter_new (GTK_TREE_MODEL (completion->priv->list_store_proposals), NULL);
-	completion->priv->model_filter_proposals = GTK_TREE_MODEL_FILTER (model);
-
-	gtk_tree_model_filter_set_visible_func (completion->priv->model_filter_proposals,
-						(GtkTreeModelFilterVisibleFunc)proposals_filter_func,
-						completion,
-						NULL);
+	completion->priv->model_proposals = 
+		gtk_source_completion_model_new ((GtkSourceCompletionModelVisibleFunc)proposals_filter_func, 
+		                                 completion);
 
-	tree_view = gtk_tree_view_new_with_model (model);
+	tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (completion->priv->model_proposals));
 	completion->priv->tree_view_proposals = tree_view;
 	
 	gtk_widget_show (tree_view);
@@ -1297,12 +1292,12 @@
 	renderer = gtk_cell_renderer_pixbuf_new ();
 	
 	gtk_tree_view_column_pack_start (column, renderer, FALSE);
-	gtk_tree_view_column_set_attributes (column, renderer, "pixbuf", COLUMN_PIXBUF, NULL);
+	gtk_tree_view_column_set_attributes (column, renderer, "pixbuf", GTK_SOURCE_COMPLETION_MODEL_COLUMN_ICON, NULL);
 	
 	renderer = gtk_cell_renderer_text_new ();
 	gtk_tree_view_column_pack_start (column, renderer, TRUE);
 
-	gtk_tree_view_column_set_attributes (column, renderer, "text", COLUMN_NAME, NULL);
+	gtk_tree_view_column_set_attributes (column, renderer, "text", GTK_SOURCE_COMPLETION_MODEL_COLUMN_LABEL, NULL);
 	gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), column);
 
 	g_signal_connect (tree_view,
@@ -1469,7 +1464,7 @@
 	g_list_free (proposals);
 }
 
-void
+gboolean
 gtk_source_completion_popup (GtkSourceCompletion *completion,
                              GList               *providers,
                              const gchar         *criteria)
@@ -1477,7 +1472,7 @@
 	GList *l;
 	gint x, y;
 
-	g_return_if_fail (GTK_IS_SOURCE_COMPLETION (completion));
+	g_return_val_if_fail (GTK_IS_SOURCE_COMPLETION (completion), FALSE);
 	
 	/* Make sure to clear any active completion */
 	gtk_source_completion_finish_real (completion);
@@ -1491,10 +1486,11 @@
 	if (providers == NULL)
 	{
 		gtk_source_completion_finish (completion);
-		return;
+		return FALSE;
 	}
 	
 	completion->priv->filter_criteria = g_strdup (criteria);
+	update_typing_offsets (completion);
 	
 	/* Make sure all providers are ours */
 	for (l = providers; l; l = g_list_next (l))
@@ -1512,6 +1508,13 @@
 	
 	completion->priv->active_providers = 
 		g_list_reverse (completion->priv->active_providers);
+	
+	/* Check if there are any completions */
+	if (gtk_source_completion_model_is_empty (completion->priv->model_proposals))
+	{
+		gtk_source_completion_finish (completion);
+		return FALSE;
+	}
 
 	update_selection_label (completion);	
 
@@ -1529,6 +1532,8 @@
 	{
 		select_first_proposal (completion);
 	}
+	
+	return TRUE;
 }
 
 /**

Modified: branches/gtksourcecompletion/gtksourceview/gtksourcecompletion.h
==============================================================================
--- branches/gtksourcecompletion/gtksourceview/gtksourcecompletion.h	(original)
+++ branches/gtksourcecompletion/gtksourceview/gtksourcecompletion.h	Mon Apr 13 17:44:09 2009
@@ -69,7 +69,7 @@
 gboolean	 gtk_source_completion_remove_provider		(GtkSourceCompletion         *completion,
 								 GtkSourceCompletionProvider *provider);
 
-void		 gtk_source_completion_popup			(GtkSourceCompletion         *completion,
+gboolean	 gtk_source_completion_popup			(GtkSourceCompletion         *completion,
 								 GList                       *providers,
 								 const gchar                 *criteria);
 

Added: branches/gtksourcecompletion/gtksourceview/gtksourcecompletionmodel.c
==============================================================================
--- (empty file)
+++ branches/gtksourcecompletion/gtksourceview/gtksourcecompletionmodel.c	Mon Apr 13 17:44:09 2009
@@ -0,0 +1,689 @@
+#include "gtksourcecompletionmodel.h"
+
+#define GTK_SOURCE_COMPLETION_MODEL_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), GTK_TYPE_SOURCE_COMPLETION_MODEL, GtkSourceCompletionModelPrivate))
+
+typedef struct
+{
+	GtkSourceCompletionProvider *provider;
+	GtkSourceCompletionProposal *proposal;
+	
+	gboolean filtered;
+} ProposalNode;
+
+struct _GtkSourceCompletionModelPrivate
+{
+	GType column_types[GTK_SOURCE_COMPLETION_MODEL_N_COLUMNS];
+	GList *store;
+	GList *last;
+	
+	guint num;
+	GHashTable *num_per_provider;
+	
+	GtkSourceCompletionModelVisibleFunc filter;
+	gpointer filter_data;
+};
+
+static void tree_model_iface_init (gpointer g_iface, gpointer iface_data);
+
+G_DEFINE_TYPE_WITH_CODE (GtkSourceCompletionModel, 
+                         gtk_source_completion_model, 
+                         G_TYPE_OBJECT,
+                         G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_MODEL,
+                                                tree_model_iface_init))
+
+
+/* Interface implementation */
+static ProposalNode *
+node_from_iter (GtkTreeIter *iter)
+{
+	return (ProposalNode *)(((GList *)iter->user_data)->data);
+}
+
+static GtkTreePath *
+path_from_list (GtkSourceCompletionModel *model,
+                GList                    *item)
+{
+	gint index = 0;
+	GList *ptr = model->priv->store;
+	ProposalNode *node;
+	
+	while (ptr && ptr != item)
+	{
+		node = (ProposalNode *)ptr->data;
+		
+		if (!node->filtered)
+		{
+			++index;
+		}
+		
+		ptr = g_list_next (ptr);
+	}
+	
+	if (ptr != item)
+	{
+		return NULL;
+	}
+	else
+	{
+		return gtk_tree_path_new_from_indices (index, -1);
+	}
+}
+
+static GtkTreeModelFlags
+tree_model_get_flags (GtkTreeModel *tree_model)
+{
+	g_return_val_if_fail (GTK_IS_SOURCE_COMPLETION_MODEL (tree_model), 0);
+
+	return 0;
+}
+
+static gint
+tree_model_get_n_columns (GtkTreeModel *tree_model)
+{
+	g_return_val_if_fail (GTK_IS_SOURCE_COMPLETION_MODEL (tree_model), 0);
+
+	return GTK_SOURCE_COMPLETION_MODEL_N_COLUMNS;
+}
+
+static GType
+tree_model_get_column_type (GtkTreeModel *tree_model,
+			    gint          index)
+{
+	g_return_val_if_fail (GTK_IS_SOURCE_COMPLETION_MODEL (tree_model), G_TYPE_INVALID);
+	g_return_val_if_fail (index >= 0 && index < GTK_SOURCE_COMPLETION_MODEL_N_COLUMNS, G_TYPE_INVALID);
+
+	return GTK_SOURCE_COMPLETION_MODEL (tree_model)->priv->column_types[index];
+}
+
+static gboolean
+get_iter_from_index (GtkSourceCompletionModel *model,
+                     GtkTreeIter              *iter,
+                     gint                      index)
+{
+	GList *item;
+	ProposalNode *node;
+
+	if (index < 0 || index >= model->priv->num)
+	{
+		return FALSE;
+	}
+	
+	item = model->priv->store;
+	
+	while (item != NULL && index >= 0)
+	{
+		node = (ProposalNode *)item->data;
+		
+		if (!node->filtered)
+		{
+			--index;
+		}
+
+		if (index != -1)
+		{
+			item = g_list_next (item);
+		}
+	}
+	
+	if (item != NULL)
+	{
+		iter->user_data = item;
+		return TRUE;
+	}
+	else
+	{
+		return FALSE;
+	}
+}
+
+static gboolean
+tree_model_get_iter (GtkTreeModel *tree_model,
+		     GtkTreeIter  *iter, 
+		     GtkTreePath  *path)
+{
+	GtkSourceCompletionModel *model;
+	gint *indices;
+	
+	g_return_val_if_fail (GTK_IS_SOURCE_COMPLETION_MODEL (tree_model), FALSE);
+	g_return_val_if_fail (iter != NULL, FALSE);
+	g_return_val_if_fail (path != NULL, FALSE);
+	
+	model = GTK_SOURCE_COMPLETION_MODEL (tree_model);
+	indices = gtk_tree_path_get_indices (path);
+	
+	return get_iter_from_index (model, iter, indices[0]);
+}
+
+static GtkTreePath *
+tree_model_get_path (GtkTreeModel *tree_model,
+		     GtkTreeIter  *iter)
+{
+	GtkSourceCompletionModel *model;
+	
+	g_return_val_if_fail (GTK_IS_SOURCE_COMPLETION_MODEL (tree_model), NULL);
+	g_return_val_if_fail (iter != NULL, NULL);
+	g_return_val_if_fail (iter->user_data != NULL, NULL);
+
+	model = GTK_SOURCE_COMPLETION_MODEL (tree_model);
+	
+	return path_from_list (model, (GList *)iter->user_data);
+}
+
+static void
+tree_model_get_value (GtkTreeModel *tree_model,
+		      GtkTreeIter  *iter, 
+		      gint          column,
+		      GValue       *value)
+{
+	ProposalNode *node;
+
+	g_return_if_fail (GTK_IS_SOURCE_COMPLETION_MODEL (tree_model));
+	g_return_if_fail (iter != NULL);
+	g_return_if_fail (iter->user_data != NULL);
+	g_return_if_fail (column >= 0 && column < GTK_SOURCE_COMPLETION_MODEL_N_COLUMNS);
+
+	node = node_from_iter (iter);
+
+	g_value_init (value, GTK_SOURCE_COMPLETION_MODEL (tree_model)->priv->column_types[column]);
+
+	switch (column)
+	{
+		case GTK_SOURCE_COMPLETION_MODEL_COLUMN_PROVIDER:
+			g_value_set_object (value, node->provider);
+			break;
+		case GTK_SOURCE_COMPLETION_MODEL_COLUMN_PROPOSAL:
+			g_value_set_object (value, node->proposal);
+			break;
+		case GTK_SOURCE_COMPLETION_MODEL_COLUMN_LABEL:
+			g_value_set_string (value, gtk_source_completion_proposal_get_label (node->proposal));
+			break;
+		case GTK_SOURCE_COMPLETION_MODEL_COLUMN_ICON:
+			g_value_set_object (value, (gpointer)gtk_source_completion_proposal_get_icon (node->proposal));
+			break;
+	}
+}
+
+static gboolean
+find_first_not_filtered (GList       *item,
+                         GtkTreeIter *iter)
+{
+	ProposalNode *node;
+
+	while (item)
+	{
+		node = (ProposalNode *)item->data;
+		
+		if (!node->filtered)
+		{
+			break;
+		}
+		
+		item = g_list_next (item);
+	}
+	
+	if (item != NULL)
+	{
+		iter->user_data = item;
+		return TRUE;
+	}
+	else
+	{
+		return FALSE;
+	}
+}
+
+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);
+	
+	item = g_list_next ((GList *)iter->user_data);
+	
+	return find_first_not_filtered (item, iter);
+}
+
+static gboolean
+tree_model_iter_children (GtkTreeModel *tree_model,
+			  GtkTreeIter  *iter,
+			  GtkTreeIter  *parent)
+{
+	g_return_val_if_fail (GTK_IS_SOURCE_COMPLETION_MODEL (tree_model), FALSE);
+	g_return_val_if_fail (iter != NULL, FALSE);
+	g_return_val_if_fail (parent == NULL || parent->user_data != NULL, FALSE);
+	
+	if (parent != NULL)
+	{
+		return FALSE;
+	}
+	else
+	{
+		return find_first_not_filtered (GTK_SOURCE_COMPLETION_MODEL (tree_model)->priv->store, iter);
+	}
+}
+
+static gboolean
+tree_model_iter_has_child (GtkTreeModel *tree_model,
+			   GtkTreeIter  *iter)
+{
+	g_return_val_if_fail (GTK_IS_SOURCE_COMPLETION_MODEL (tree_model), FALSE);
+	g_return_val_if_fail (iter != NULL, FALSE);
+	
+	return FALSE;
+}
+
+static gint
+tree_model_iter_n_children (GtkTreeModel *tree_model,
+			    GtkTreeIter  *iter)
+{
+	g_return_val_if_fail (GTK_IS_SOURCE_COMPLETION_MODEL (tree_model), 0);
+	g_return_val_if_fail (iter == NULL || iter->user_data != NULL, 0);
+	
+	if (iter == NULL)
+	{
+		return GTK_SOURCE_COMPLETION_MODEL (tree_model)->priv->num;
+	}
+	else
+	{
+		return 0;
+	}
+}
+
+static gboolean
+tree_model_iter_nth_child (GtkTreeModel *tree_model,
+			   GtkTreeIter  *iter,
+			   GtkTreeIter  *parent, 
+			   gint          n)
+{
+	g_return_val_if_fail (GTK_IS_SOURCE_COMPLETION_MODEL (tree_model), FALSE);
+	g_return_val_if_fail (iter != NULL, FALSE);
+	g_return_val_if_fail (parent == NULL || parent->user_data != NULL, FALSE);
+
+	if (parent != NULL)
+	{
+		return FALSE;
+	}
+	else
+	{
+		return get_iter_from_index (GTK_SOURCE_COMPLETION_MODEL (tree_model), 
+		                            iter, 
+		                            n);
+	}
+}
+
+static gboolean
+tree_model_iter_parent (GtkTreeModel *tree_model,
+			GtkTreeIter  *iter,
+			GtkTreeIter  *child)
+{
+	g_return_val_if_fail (GTK_IS_SOURCE_COMPLETION_MODEL (tree_model), FALSE);
+	g_return_val_if_fail (iter != NULL, FALSE);
+	g_return_val_if_fail (child != NULL, FALSE);
+	
+	iter->user_data = NULL;
+	return FALSE;
+}
+
+static void
+tree_model_row_inserted (GtkTreeModel *tree_model,
+			 GtkTreePath  *path,
+			 GtkTreeIter  *iter)
+{
+}
+
+static void
+tree_model_iface_init (gpointer g_iface, 
+                       gpointer iface_data)
+{
+	GtkTreeModelIface *iface = (GtkTreeModelIface *)g_iface;
+
+	iface->get_flags = tree_model_get_flags;
+	iface->get_n_columns = tree_model_get_n_columns;
+	iface->get_column_type = tree_model_get_column_type;
+	iface->get_iter = tree_model_get_iter;
+	iface->get_path = tree_model_get_path;
+	iface->get_value = tree_model_get_value;
+	iface->iter_next = tree_model_iter_next;
+	iface->iter_children = tree_model_iter_children;
+	iface->iter_has_child = tree_model_iter_has_child;
+	iface->iter_n_children = tree_model_iter_n_children;
+	iface->iter_nth_child = tree_model_iter_nth_child;
+	iface->iter_parent = tree_model_iter_parent;
+	iface->row_inserted = tree_model_row_inserted;
+}
+
+static void
+gtk_source_completion_model_finalize (GObject *object)
+{
+	GtkSourceCompletionModel *model = GTK_SOURCE_COMPLETION_MODEL (object);
+	
+	g_hash_table_destroy (model->priv->num_per_provider);
+
+	G_OBJECT_CLASS (gtk_source_completion_model_parent_class)->finalize (object);
+}
+
+static void
+gtk_source_completion_model_class_init (GtkSourceCompletionModelClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+	
+	object_class->finalize = gtk_source_completion_model_finalize;
+
+	g_type_class_add_private (object_class, sizeof(GtkSourceCompletionModelPrivate));
+}
+
+static void
+free_num (gpointer data)
+{
+	g_slice_free (guint, data);
+}
+
+static void
+gtk_source_completion_model_init (GtkSourceCompletionModel *self)
+{
+	self->priv = GTK_SOURCE_COMPLETION_MODEL_GET_PRIVATE (self);
+	
+	self->priv->column_types[GTK_SOURCE_COMPLETION_MODEL_COLUMN_PROVIDER] = G_TYPE_OBJECT;
+	self->priv->column_types[GTK_SOURCE_COMPLETION_MODEL_COLUMN_PROPOSAL] = G_TYPE_OBJECT;
+	self->priv->column_types[GTK_SOURCE_COMPLETION_MODEL_COLUMN_LABEL] = G_TYPE_STRING;
+	self->priv->column_types[GTK_SOURCE_COMPLETION_MODEL_COLUMN_ICON] = GDK_TYPE_PIXBUF;
+	
+	self->priv->num_per_provider = g_hash_table_new_full (g_direct_hash,
+	                                                      g_direct_equal,
+	                                                      NULL,
+	                                                      free_num);
+}
+
+static void
+num_inc (GtkSourceCompletionModel    *model,
+         GtkSourceCompletionProvider *provider)
+{
+	guint *num;
+	++model->priv->num;
+
+	num = g_hash_table_lookup (model->priv->num_per_provider, provider);
+	
+	if (num != NULL)
+	{
+		++(*num);
+	}
+	else
+	{
+		num = g_slice_new (guint);
+		*num = 1;
+
+		g_hash_table_insert (model->priv->num_per_provider, provider, num);
+	}
+	
+}
+
+static void
+num_dec (GtkSourceCompletionModel    *model,
+         GtkSourceCompletionProvider *provider)
+{
+	guint *num;
+
+	--model->priv->num;
+	
+	num = g_hash_table_lookup (model->priv->num_per_provider, provider);
+	
+	if (num != NULL && *num > 0)
+	{
+		--(*num);
+	}
+}
+
+static gboolean
+node_update_filter_state (GtkSourceCompletionModel *model, 
+                          ProposalNode             *node)
+{
+	gboolean ret;
+	
+	ret = node->filtered;
+	
+	node->filtered = !model->priv->filter (model, 
+	                                       node->provider, 
+	                                       node->proposal, 
+	                                       model->priv->filter_data);
+
+	return ret;
+}
+
+static void
+free_node (ProposalNode *node)
+{
+	g_object_unref (node->provider);
+	g_object_unref (node->proposal);
+	
+	g_slice_free (ProposalNode, node);
+}
+
+static void
+remove_node (GtkSourceCompletionModel *model,
+             GList                    *item)
+{
+	ProposalNode *node;
+	GtkTreePath *path;
+	gboolean filtered;
+	GtkSourceCompletionProvider *provider;
+	
+	path = path_from_list (model, item);
+
+	node = (ProposalNode *)item->data;
+	provider = g_object_ref (node->provider);
+
+	filtered = node->filtered;
+	free_node (node);
+
+	if (item == model->priv->last)
+	{
+		model->priv->last = item->prev;
+	}
+
+	model->priv->store = g_list_remove_link (model->priv->store, item);
+	
+	if (!filtered)
+	{
+		num_dec (model, provider);
+		gtk_tree_model_row_deleted (GTK_TREE_MODEL (model), path);
+	}
+
+	gtk_tree_path_free (path);
+	g_object_unref (provider);
+}
+
+/* Public */
+GtkSourceCompletionModel*
+gtk_source_completion_model_new (GtkSourceCompletionModelVisibleFunc func,
+                                 gpointer                            userdata)
+{
+	GtkSourceCompletionModel *model = g_object_new (GTK_TYPE_SOURCE_COMPLETION_MODEL, NULL);
+	
+	model->priv->filter = func;
+	model->priv->filter_data = userdata;
+
+	return model;
+}
+
+gboolean 
+gtk_source_completion_model_append (GtkSourceCompletionModel    *model,
+                                    GtkSourceCompletionProvider *provider,
+                                    GtkSourceCompletionProposal *proposal,
+                                    GtkTreeIter                 *iter)
+{
+	ProposalNode *node;
+	GList *item;
+	GtkTreePath *path;
+	
+	g_return_val_if_fail (GTK_IS_SOURCE_COMPLETION_MODEL (model), FALSE);
+	g_return_val_if_fail (GTK_IS_SOURCE_COMPLETION_PROVIDER (provider), FALSE);
+	g_return_val_if_fail (GTK_IS_SOURCE_COMPLETION_PROPOSAL (proposal), FALSE);
+	g_return_val_if_fail (iter != NULL, FALSE);
+	
+	node = g_slice_new (ProposalNode);
+	node->provider = g_object_ref (provider);
+	node->proposal = g_object_ref (proposal);
+
+	node_update_filter_state (model, node);
+	
+	item = model->priv->last;
+	item = g_list_append (item, node);
+	
+	if (model->priv->store == NULL)
+	{
+		model->priv->store = item;
+	}
+	else
+	{
+		item = item->next;
+	}
+	
+	model->priv->last = item;
+	iter->user_data = item;
+	
+	if (!node->filtered)
+	{
+		path = path_from_list (model, item);
+		
+		num_inc (model, node->provider);
+
+		gtk_tree_model_row_inserted (GTK_TREE_MODEL (model), path, iter);
+		gtk_tree_path_free (path);
+	}
+
+	return TRUE;
+}
+
+gboolean 
+gtk_source_completion_model_remove (GtkSourceCompletionModel    *model,
+                                    GtkTreeIter                 *iter)
+{
+	g_return_val_if_fail (GTK_IS_SOURCE_COMPLETION_MODEL (model), FALSE);
+	g_return_val_if_fail (iter != NULL, FALSE);
+	g_return_val_if_fail (iter->user_data != NULL, FALSE);
+	
+	remove_node (model, (GList *)iter->user_data);
+	return TRUE;
+}
+
+void
+gtk_source_completion_model_clear (GtkSourceCompletionModel *model)
+{
+	GtkTreePath *path;
+	ProposalNode *node;
+	GList *list;
+	gboolean filtered;
+	
+	g_return_if_fail (GTK_IS_SOURCE_COMPLETION_MODEL (model));
+	
+	path = gtk_tree_path_new_first ();
+	list = model->priv->store;
+	
+	while (model->priv->store)
+	{
+		node = (ProposalNode *)model->priv->store->data;
+		filtered = node->filtered;
+
+		free_node (node);
+		
+		model->priv->store = model->priv->store->next;
+		
+		if (model->priv->store == NULL)
+		{
+			model->priv->last = NULL;
+		}
+		
+		if (!filtered)
+		{
+			num_dec (model, node->provider);
+			gtk_tree_model_row_deleted (GTK_TREE_MODEL (model), path);
+		}
+	}
+	
+	g_list_free (list);
+	gtk_tree_path_free (path);
+	
+	g_hash_table_remove_all (model->priv->num_per_provider);
+}
+
+void
+gtk_source_completion_model_refilter (GtkSourceCompletionModel *model)
+{
+	GList *item;
+	gboolean filtered;
+	ProposalNode *node;
+	GtkTreePath *path;
+	GtkTreeIter iter;
+
+	g_return_if_fail (GTK_IS_SOURCE_COMPLETION_MODEL (model));
+	
+	path = gtk_tree_path_new_first ();
+	
+	for (item = model->priv->store; item != NULL; item = g_list_next (item))
+	{
+		iter.user_data = item;
+
+		node = (ProposalNode *)item->data;
+		filtered = node_update_filter_state (model, node);
+		
+		if (filtered == node->filtered)
+		{
+			/* 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);
+			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);
+			gtk_tree_model_row_deleted (GTK_TREE_MODEL (model),
+			                            path);
+		}
+	}
+
+	gtk_tree_path_free (path);
+}
+
+gboolean
+gtk_source_completion_model_is_empty (GtkSourceCompletionModel *model)
+{
+	g_return_val_if_fail (GTK_IS_SOURCE_COMPLETION_MODEL (model), FALSE);
+	
+	return model->priv->num == 0;
+}
+
+guint
+gtk_source_completion_model_n_proposals (GtkSourceCompletionModel    *model,
+                                         GtkSourceCompletionProvider *provider)
+{
+	guint *num;
+	
+	g_return_val_if_fail (GTK_IS_SOURCE_COMPLETION_MODEL (model), 0);
+	g_return_val_if_fail (GTK_IS_SOURCE_COMPLETION_PROVIDER (provider), 0);
+	
+	num = g_hash_table_lookup (model->priv->num_per_provider, provider);
+	
+	if (num == NULL)
+	{
+		return 0;
+	}
+	else
+	{
+		return *num;
+	}
+}
+

Added: branches/gtksourcecompletion/gtksourceview/gtksourcecompletionmodel.h
==============================================================================
--- (empty file)
+++ branches/gtksourcecompletion/gtksourceview/gtksourcecompletionmodel.h	Mon Apr 13 17:44:09 2009
@@ -0,0 +1,93 @@
+/*
+ * gtksourcecompletionmodel.h
+ * This file is part of gtksourcecompletion
+ *
+ * Copyright (C) 2009 - Jesse van den Kieboom
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifndef __GTK_SOURCE_COMPLETION_MODEL_H__
+#define __GTK_SOURCE_COMPLETION_MODEL_H__
+
+#include <gtk/gtk.h>
+#include <gtksourceview/gtksourcecompletionprovider.h>
+#include <gtksourceview/gtksourcecompletionproposal.h>
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_SOURCE_COMPLETION_MODEL		(gtk_source_completion_model_get_type ())
+#define GTK_SOURCE_COMPLETION_MODEL(obj)		(G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_SOURCE_COMPLETION_MODEL, GtkSourceCompletionModel))
+#define GTK_SOURCE_COMPLETION_MODEL_CONST(obj)		(G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_SOURCE_COMPLETION_MODEL, GtkSourceCompletionModel const))
+#define GTK_SOURCE_COMPLETION_MODEL_CLASS(klass)	(G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_SOURCE_COMPLETION_MODEL, GtkSourceCompletionModelClass))
+#define GTK_IS_SOURCE_COMPLETION_MODEL(obj)		(G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_SOURCE_COMPLETION_MODEL))
+#define GTK_IS_SOURCE_COMPLETION_MODEL_CLASS(klass)	(G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_SOURCE_COMPLETION_MODEL))
+#define GTK_SOURCE_COMPLETION_MODEL_GET_CLASS(obj)	(G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_SOURCE_COMPLETION_MODEL, GtkSourceCompletionModelClass))
+
+typedef struct _GtkSourceCompletionModel	GtkSourceCompletionModel;
+typedef struct _GtkSourceCompletionModelClass	GtkSourceCompletionModelClass;
+typedef struct _GtkSourceCompletionModelPrivate	GtkSourceCompletionModelPrivate;
+
+struct _GtkSourceCompletionModel {
+	GObject parent;
+	
+	GtkSourceCompletionModelPrivate *priv;
+};
+
+struct _GtkSourceCompletionModelClass {
+	GObjectClass parent_class;
+};
+
+enum
+{
+	GTK_SOURCE_COMPLETION_MODEL_COLUMN_LABEL,
+	GTK_SOURCE_COMPLETION_MODEL_COLUMN_ICON,
+	GTK_SOURCE_COMPLETION_MODEL_COLUMN_PROPOSAL,
+	GTK_SOURCE_COMPLETION_MODEL_COLUMN_PROVIDER,
+	GTK_SOURCE_COMPLETION_MODEL_N_COLUMNS
+};
+
+typedef gboolean (* 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 	(GtkSourceCompletionModelVisibleFunc func,
+							 gpointer                            userdata);
+
+gboolean 	gtk_source_completion_model_append 	(GtkSourceCompletionModel           *model,
+							 GtkSourceCompletionProvider        *provider,
+							 GtkSourceCompletionProposal        *proposal,
+							 GtkTreeIter                        *iter);
+
+gboolean 	gtk_source_completion_model_remove 	(GtkSourceCompletionModel           *model, 
+							 GtkTreeIter                        *iter);
+
+gboolean	gtk_source_completion_model_is_empty 	(GtkSourceCompletionModel           *model);
+guint		gtk_source_completion_model_n_proposals (GtkSourceCompletionModel           *model,
+                                                         GtkSourceCompletionProvider        *provider);
+
+void 		gtk_source_completion_model_clear 	(GtkSourceCompletionModel           *model);
+
+void		gtk_source_completion_model_refilter	(GtkSourceCompletionModel           *model);
+
+G_END_DECLS
+
+#endif /* __GTK_SOURCE_COMPLETION_MODEL_H__ */
+

Modified: branches/gtksourcecompletion/tests/completion-simple.c
==============================================================================
--- branches/gtksourcecompletion/tests/completion-simple.c	(original)
+++ branches/gtksourcecompletion/tests/completion-simple.c	Mon Apr 13 17:44:09 2009
@@ -160,18 +160,15 @@
 create_completion(void)
 {
 	GscProviderTest *prov_test1;
-	GscProviderTest *prov_test2;
-	//GscProviderDevhelp *prov_devhelp;
+	GscProviderDevhelp *prov_devhelp;
 	
 	comp = gtk_source_view_get_completion (GTK_SOURCE_VIEW (view));
 	
 	prov_test1 = gsc_provider_test_new ("Test 1");
-	prov_test2 = gsc_provider_test_new ("Test 2");
-	//prov_devhelp = gsc_provider_devhelp_new ();
+	prov_devhelp = gsc_provider_devhelp_new ();
 	
 	gtk_source_completion_add_provider (comp, GTK_SOURCE_COMPLETION_PROVIDER (prov_test1));
-	gtk_source_completion_add_provider (comp, GTK_SOURCE_COMPLETION_PROVIDER (prov_test2));
-	//gtk_source_completion_add_provider (comp, GTK_SOURCE_COMPLETION_PROVIDER (prov_devhelp));
+	gtk_source_completion_add_provider (comp, GTK_SOURCE_COMPLETION_PROVIDER (prov_devhelp));
 }
 
 int
@@ -190,5 +187,3 @@
 	gtk_main ();
 	return 0;
 }
-
-

Modified: branches/gtksourcecompletion/tests/gsc-provider-test.c
==============================================================================
--- branches/gtksourcecompletion/tests/gsc-provider-test.c	(original)
+++ branches/gtksourcecompletion/tests/gsc-provider-test.c	Mon Apr 13 17:44:09 2009
@@ -55,17 +55,31 @@
 {
 	GList *list = NULL;
 	
-	list = append_item (list, "Proposal 1.1", NULL, "Info proposal 1.1");
-	list = append_item (list, "Proposal 1.2", NULL, "Info proposal 1.2");
-	list = append_item (list, "Proposal 1.3", NULL, "Info proposal 1.3");
-	
-	list = append_item (list, "Proposal 2.1", NULL, "Info proposal 2.1");
-	list = append_item (list, "Proposal 2.2", NULL, "Info proposal 2.2");
-	list = append_item (list, "Proposal 2.3", NULL, "Info proposal 2.3");
-
+	list = append_item (list, "aa", NULL, "Info proposal 1.1");
+	list = append_item (list, "ab", NULL, "Info proposal 1.2");
+	list = append_item (list, "bc", NULL, "Info proposal 1.3");
+	list = append_item (list, "bd", NULL, "Info proposal 1.3");
+	
 	return list;
 }
 
+static gboolean
+gsc_provider_test_filter_proposal (GtkSourceCompletionProvider *provider,
+                                   GtkSourceCompletionProposal *proposal,
+                                   const gchar                 *criteria)
+{
+	const gchar *label;
+	
+	label = gtk_source_completion_proposal_get_label (proposal);
+	return g_str_has_prefix (label, criteria);
+}
+
+static gboolean
+gsc_provider_test_can_auto_complete (GtkSourceCompletionProvider *provider)
+{
+	return TRUE;
+}
+
 static void 
 gsc_provider_test_finalize (GObject *object)
 {
@@ -92,6 +106,8 @@
 {
 	iface->get_name = gsc_provider_test_get_name;
 	iface->get_proposals = gsc_provider_test_get_proposals;
+	iface->filter_proposal = gsc_provider_test_filter_proposal;
+	iface->can_auto_complete = gsc_provider_test_can_auto_complete;
 }
 
 static void 



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