[epiphany/history-rewrite-second: 28/28] Hook the new history to the URL entry



commit a09c43f7972b9f3b317eb274a6402a0f106a7c27
Author: Xan Lopez <xan igalia com>
Date:   Tue Feb 28 17:39:45 2012 +0100

    Hook the new history to the URL entry
    
    We now fetch the history from the SQL backend using a service thread,
    and merge the results with our old bookmark data.
    
    TODOs:
    
    - You can see how the completion popup gets smaller when the next
      batch of results is smaller than the previous one. This is ugly.
    - It seems we don't set the favicon correctly in some cases.

 embed/ephy-browse-history.c       |    5 +
 embed/ephy-browse-history.h       |    1 +
 lib/widgets/ephy-location-entry.c |  197 +-------
 src/Makefile.am                   |    1 +
 src/ephy-completion-model.c       | 1038 +++++++++++++++++--------------------
 src/ephy-completion-model.h       |   16 +-
 src/ephy-location-controller.c    |   57 +--
 7 files changed, 533 insertions(+), 782 deletions(-)
---
diff --git a/embed/ephy-browse-history.c b/embed/ephy-browse-history.c
index 3295f85..c58eaea 100644
--- a/embed/ephy-browse-history.c
+++ b/embed/ephy-browse-history.c
@@ -181,6 +181,7 @@ ephy_browse_history_get_url (EphyBrowseHistory *history,
 void
 ephy_browse_history_find_urls (EphyBrowseHistory *history,
                                gint64 from, gint64 to,
+                               guint limit,
                                GList *substring_list,
                                EphyHistoryJobCallback callback,
                                gpointer user_data)
@@ -193,6 +194,10 @@ ephy_browse_history_find_urls (EphyBrowseHistory *history,
   query->from = from;
   query->to = to;
   query->substring_list = substring_list;
+  query->sort_type = EPHY_HISTORY_SORT_MV;
+
+  if (limit != 0)
+    query->limit = limit;
 
   ephy_history_service_query_urls (history->priv->history_service,
                                    query, callback, user_data);
diff --git a/embed/ephy-browse-history.h b/embed/ephy-browse-history.h
index abb6134..980134a 100644
--- a/embed/ephy-browse-history.h
+++ b/embed/ephy-browse-history.h
@@ -93,6 +93,7 @@ void              ephy_browse_history_get_url (EphyBrowseHistory *history,
 
 void             ephy_browse_history_find_urls (EphyBrowseHistory *history,
                                                 gint64 from, gint64 to,
+                                                guint limit,
                                                 GList *substring_list,
                                                 EphyHistoryJobCallback callback,
                                                 gpointer user_data);
diff --git a/lib/widgets/ephy-location-entry.c b/lib/widgets/ephy-location-entry.c
index 24e08d5..f132c6a 100644
--- a/lib/widgets/ephy-location-entry.c
+++ b/lib/widgets/ephy-location-entry.c
@@ -51,6 +51,8 @@ struct _EphyLocationEntryPrivate
 {
 	GIcon *lock_gicon;
 	GdkPixbuf *favicon;
+	GtkTreeModel *model;
+	GtkEntryCompletion *completion;
 
 	GSList *search_terms;
 
@@ -112,17 +114,6 @@ static gint signals[LAST_SIGNAL] = { 0 };
 
 G_DEFINE_TYPE (EphyLocationEntry, ephy_location_entry, GTK_TYPE_ENTRY)
 
-inline static void
-free_search_terms (GSList *search_terms)
-{
-	GSList *iter;
-	
-	for (iter = search_terms; iter != NULL; iter = iter->next)
-		g_regex_unref ((GRegex*)iter->data);
-	
-	g_slist_free (search_terms);
-}
-
 static void
 ephy_location_entry_finalize (GObject *object)
 {
@@ -141,12 +132,6 @@ ephy_location_entry_finalize (GObject *object)
 		g_object_unref (priv->lock_gicon);
 	}
 
-	if (priv->search_terms)
-	{
-		free_search_terms (priv->search_terms);
-		priv->search_terms = NULL;
-	}
-
 	G_OBJECT_CLASS (ephy_location_entry_parent_class)->finalize (object);
 }
 
@@ -278,8 +263,6 @@ editable_changed_cb (GtkEditable *editable,
 		     EphyLocationEntry *entry)
 {
 	EphyLocationEntryPrivate *priv = entry->priv;
-	const char *text;
-	char *pattern;
 
 	update_address_state (entry);
 
@@ -291,104 +274,6 @@ editable_changed_cb (GtkEditable *editable,
 		priv->can_redo = FALSE;
 	}	
 	
-	if (priv->search_terms)
-	{
-		free_search_terms (priv->search_terms);
-		priv->search_terms = NULL;
-	}
-
-	text = gtk_entry_get_text (GTK_ENTRY (editable));
-
-	/*
-	 * user is specifying a regular expression, so we will
-	 * have only one search term
-	 */
-	if (g_str_has_prefix (text, "re:"))
-	{
-		GRegex *regex;
-		pattern = g_strdup (text+3);
-		regex = g_regex_new (pattern,
-				     G_REGEX_CASELESS | G_REGEX_OPTIMIZE,
-				     G_REGEX_MATCH_NOTEMPTY, NULL);
-		priv->search_terms = g_slist_append (priv->search_terms, regex);
-		g_free (pattern);
-	}
-	else
-	{
-		const char *current;
-		const char *ptr;
-		char *tmp;
-		char *term;
-		GRegex *term_regex;
-		GRegex *quote_regex;
-		gint count;
-		gboolean inside_quotes = FALSE;
-
-		quote_regex = g_regex_new ("\"", G_REGEX_OPTIMIZE,
-					   G_REGEX_MATCH_NOTEMPTY, NULL);
-		
-		/*
-		 * This code loops through the string using pointer arythmetics.
-		 * Although the string we are handling may contain UTF-8 chars
-		 * this works because only ASCII chars affect what is actually
-		 * copied from the string as a search term.
-		 */
-		for (count = 0, current = ptr = text; ptr[0] != '\0'; ptr++, count++)
-		{
-			/*
-			 * If we found a double quote character; we will 
-			 * consume bytes up until the next quote, or
-			 * end of line;
-			 */
-			if (ptr[0] == '"')
-				inside_quotes = !inside_quotes;
-
-			/*
-			 * If we found a space, and we are not looking for a
-			 * closing double quote, or if the next char is the
-			 * end of the string, append what we have already as
-			 * a search term.
-			 */
-			if (((ptr[0] == ' ') && (!inside_quotes)) || ptr[1] == '\0')
-			{
-				/*
-				 * We special-case the end of the line because
-				 * we would otherwise not copy the last character
-				 * of the search string, since the for loop will
-				 * stop before that.
-				 */
-				if (ptr[1] == '\0')
-					count++;
-				
-				/*
-				 * remove quotes, and quote any regex-sensitive
-				 * characters
-				 */
-				tmp = g_regex_escape_string (current, count);
-				term = g_regex_replace (quote_regex, tmp, -1, 0,
-							"", G_REGEX_MATCH_NOTEMPTY, NULL);
-				g_strstrip (term);
-				g_free (tmp);
-
-				/* we don't want empty search terms */
-				if (term[0] != '\0')
-				{
-					term_regex = g_regex_new (term,
-								  G_REGEX_CASELESS | G_REGEX_OPTIMIZE,
-								  G_REGEX_MATCH_NOTEMPTY, NULL);
-					priv->search_terms = g_slist_append (priv->search_terms, term_regex);
-				}
-				g_free (term);
-
-				 /* count will be incremented by the for loop */
-				count = -1;
-				current = ptr + 1;
-			}
-		}
-
-		g_regex_unref (quote_regex);
-	}
-
 	g_signal_emit (entry, signals[USER_CHANGED], 0);
 }
 
@@ -894,7 +779,6 @@ ephy_location_entry_init (EphyLocationEntry *le)
 	p->user_changed = FALSE;
 	p->block_update = FALSE;
 	p->saved_text = NULL;
-	p->search_terms = NULL;
 	p->show_lock = FALSE;
 	p->dns_prefetch_handler = 0;
 
@@ -981,18 +865,15 @@ cursor_on_match_cb  (GtkEntryCompletion *completion,
 
 static void
 textcell_data_func (GtkCellLayout *cell_layout,
-			GtkCellRenderer *cell,
-			GtkTreeModel *tree_model,
-			GtkTreeIter *iter,
-			gpointer data)
+		    GtkCellRenderer *cell,
+		    GtkTreeModel *tree_model,
+		    GtkTreeIter *iter,
+		    gpointer data)
 {
 	GtkWidget *entry;
 	EphyLocationEntryPrivate *priv;
 	PangoAttrList *list;
 	PangoAttribute *att;
-	GMatchInfo *match;
-
-	int start, end;
 
 	char *ctext;
 	char *title;
@@ -1038,38 +919,6 @@ textcell_data_func (GtkCellLayout *cell_layout,
 		ctext = title;
 	}
 
-	if (priv->search_terms)
-	{
-		GSList *iter;
-		GRegex *regex;
-
-		for (iter = priv->search_terms; iter != NULL; iter = iter->next)
-		{
-			regex = (GRegex*) iter->data;
-			g_regex_match (regex, ctext, G_REGEX_MATCH_NOTEMPTY, &match);
-
-			while (g_match_info_matches (match))
-			{
-				g_match_info_fetch_pos (match, 0, &start, &end);
-
-				att = pango_attr_weight_new (PANGO_WEIGHT_BOLD);
-				att->start_index = start;
-				att->end_index = end;
-
-				pango_attr_list_insert (list, att);
-				g_match_info_next (match, NULL);
-			}
-
-			g_match_info_free (match);
-			match = NULL;
-		}
-
-	}
-
-	g_object_set (cell,
-		      "attributes", list,
-		      NULL);
-
 	g_value_init (&text, G_TYPE_STRING);
 	g_value_take_string (&text, ctext);
 	g_object_set_property (G_OBJECT (cell), "text", &text);
@@ -1159,28 +1008,20 @@ ephy_location_entry_set_completion (EphyLocationEntry *entry,
 				    guint extra_col,
 				    guint favicon_col)
 {
-	GtkTreeModel *sort_model;
 	GtkEntryCompletion *completion;
 	GtkCellRenderer *cell;
+	EphyLocationEntryPrivate *priv = entry->priv;
 
-	entry->priv->text_col = text_col;
-	entry->priv->action_col = action_col;
-	entry->priv->keywords_col = keywords_col;
-	entry->priv->relevance_col = relevance_col;
-	entry->priv->url_col = url_col;
-	entry->priv->extra_col = extra_col;
-	entry->priv->favicon_col = favicon_col;
-
-	sort_model = gtk_tree_model_sort_new_with_model (model);
-
-	gtk_tree_sortable_set_sort_column_id 
-			(GTK_TREE_SORTABLE (sort_model),
-			 entry->priv->relevance_col,
-			 GTK_SORT_DESCENDING);
+	priv->text_col = text_col;
+	priv->action_col = action_col;
+	priv->keywords_col = keywords_col;
+	priv->relevance_col = relevance_col;
+	priv->url_col = url_col;
+	priv->extra_col = extra_col;
+	priv->favicon_col = favicon_col;
 
 	completion = gtk_entry_completion_new ();
-	gtk_entry_completion_set_model (completion, sort_model);
-	g_object_unref (sort_model);
+	gtk_entry_completion_set_model (completion, model);
 	g_signal_connect (completion, "match-selected",
 			  G_CALLBACK (match_selected_cb), entry);
 	g_signal_connect_after (completion, "action-activated",
@@ -1213,9 +1054,9 @@ ephy_location_entry_set_completion (EphyLocationEntry *entry,
 	gtk_cell_renderer_text_set_fixed_height_from_font (GTK_CELL_RENDERER_TEXT (cell), 2);
 
 	gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (completion),
-					cell, textcell_data_func,
-					entry,
-					NULL);
+					    cell, textcell_data_func,
+					    entry,
+					    NULL);
 
 	cell = gtk_cell_renderer_pixbuf_new ();
 	gtk_cell_layout_pack_end (GTK_CELL_LAYOUT (completion),
@@ -1230,6 +1071,8 @@ ephy_location_entry_set_completion (EphyLocationEntry *entry,
 			  G_CALLBACK (cursor_on_match_cb), entry);
 
 	gtk_entry_set_completion (GTK_ENTRY (entry), completion);
+
+	priv->completion = completion;
 	g_object_unref (completion);
 }
 
diff --git a/src/Makefile.am b/src/Makefile.am
index 70f5574..56e699b 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -92,6 +92,7 @@ libephymain_la_CPPFLAGS = \
 	-I$(top_srcdir)/embed 		\
 	-I$(top_srcdir)/lib   		\
 	-I$(top_srcdir)/lib/egg		\
+	-I$(top_srcdir)/lib/history	\
 	-I$(top_srcdir)/lib/widgets   	\
 	-I$(top_srcdir)/src/bookmarks   \
 	-DEXTENSIONS_DIR=\""$(libdir)/epiphany/$(EPIPHANY_API_VERSION)/extensions"\" 	\
diff --git a/src/ephy-completion-model.c b/src/ephy-completion-model.c
index ef67185..09873b2 100644
--- a/src/ephy-completion-model.c
+++ b/src/ephy-completion-model.c
@@ -1,6 +1,6 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* 
- *  Copyright  2002 Jorn Baayen <jorn nl linux org>
+ *  Copyright  2012 Igalia S.L.
  *
  *  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
@@ -21,636 +21,566 @@
 #include "config.h"
 #include "ephy-completion-model.h"
 
+#include "ephy-browse-history.h"
+#include "ephy-embed-shell.h"
 #include "ephy-favicon-cache.h"
 #include "ephy-history.h"
-#include "ephy-node.h"
 #include "ephy-shell.h"
+#include "ephy-tree-model-node.h"
 
 #include <string.h>
 
-static void ephy_completion_model_class_init (EphyCompletionModelClass *klass);
-static void ephy_completion_model_init (EphyCompletionModel *model);
-static void ephy_completion_model_tree_model_init (GtkTreeModelIface *iface);
+G_DEFINE_TYPE (EphyCompletionModel, ephy_completion_model, GTK_TYPE_LIST_STORE)
 
 #define EPHY_COMPLETION_MODEL_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), EPHY_TYPE_COMPLETION_MODEL, EphyCompletionModelPrivate))
 
-struct _EphyCompletionModelPrivate
-{
-	EphyHistory *history_service;
-	EphyBookmarks *bookmarks_service;
-	EphyFaviconCache *favicon_cache;
-
-	EphyNode *history;
-	EphyNode *bookmarks;
-	int stamp;
-};
+struct _EphyCompletionModelPrivate {
+  EphyBrowseHistory *browse_history;
+  EphyHistory *legacy_history_service;
+  EphyFaviconCache *favicon_cache;
 
-enum
-{
-	HISTORY_GROUP,
-	BOOKMARKS_GROUP
+  EphyNode *bookmarks;
+  GSList *search_terms;
 };
 
-G_DEFINE_TYPE_WITH_CODE (EphyCompletionModel, ephy_completion_model, G_TYPE_OBJECT,
-			 G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_MODEL,
-						ephy_completion_model_tree_model_init))
-
-static void
-ephy_completion_model_class_init (EphyCompletionModelClass *klass)
-{
-	GObjectClass *object_class = G_OBJECT_CLASS (klass);
-
-	g_type_class_add_private (object_class, sizeof (EphyCompletionModelPrivate));
-}
-
-static GtkTreePath *
-get_path_real (EphyCompletionModel *model,
-	       EphyNode *root,
-	       EphyNode *child)
-{
-	GtkTreePath *retval;
-	int index;
-
-	retval = gtk_tree_path_new ();
-	index = ephy_node_get_child_index (root, child);
-
-	if (root == model->priv->bookmarks)
-	{
-		index += ephy_node_get_n_children (model->priv->history);
-	}
-
-	gtk_tree_path_append_index (retval, index);
-
-	return retval;
-}
-
 static void
-node_iter_from_node (EphyCompletionModel *model,
-		     EphyNode *root,
-		     EphyNode *child,
-		     GtkTreeIter *iter)
+ephy_completion_model_constructed (GObject *object)
 {
-	iter->stamp = model->priv->stamp;
-	iter->user_data = child;
-	iter->user_data2 = root;
-}
+  GType types[N_COL] = { G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
+                         G_TYPE_INT, G_TYPE_STRING, G_TYPE_BOOLEAN,
+                         GDK_TYPE_PIXBUF };
 
-static EphyNode *
-get_index_root (EphyCompletionModel *model, int *index)
-{
-	int children;
-
-	children = ephy_node_get_n_children (model->priv->history);
-
-	if (*index >= children)
-	{
-		*index = *index - children;
-
-		if (*index < ephy_node_get_n_children (model->priv->bookmarks))
-		{
-			return model->priv->bookmarks;
-		}
-		else
-		{
-			return NULL;
-		}
-	}
-	else
-	{
-		return model->priv->history;
-	}
+  gtk_list_store_set_column_types (GTK_LIST_STORE (object),
+                                   N_COL,
+                                   types);
 }
 
 static void
-root_child_removed_cb (EphyNode *node,
-		       EphyNode *child,
-		       guint old_index,
-		       EphyCompletionModel *model)
-{
-	GtkTreePath *path;
-	guint index;
-
-	path = gtk_tree_path_new ();
-
-	index = old_index;
-	if (node == model->priv->bookmarks)
-	{
-		index += ephy_node_get_n_children (model->priv->history);
-	}
-	gtk_tree_path_append_index (path, index);
-
-	gtk_tree_model_row_deleted (GTK_TREE_MODEL (model), path);
-	gtk_tree_path_free (path);
+free_search_terms (GSList *search_terms)
+{
+  GSList *iter;
+  
+  for (iter = search_terms; iter != NULL; iter = iter->next)
+    g_regex_unref ((GRegex*)iter->data);
+  
+  g_slist_free (search_terms);
 }
 
 static void
-root_child_added_cb (EphyNode *node,
-		     EphyNode *child,
-		     EphyCompletionModel *model)
+ephy_completion_model_finalize (GObject *object)
 {
-	GtkTreePath *path;
-	GtkTreeIter iter;
+  EphyCompletionModelPrivate *priv = EPHY_COMPLETION_MODEL (object)->priv;
 
-	node_iter_from_node (model, node, child, &iter);
+  if (priv->search_terms) {
+    free_search_terms (priv->search_terms);
+    priv->search_terms = NULL;
+  }
 
-	path = get_path_real (model, node, child);
-	gtk_tree_model_row_inserted (GTK_TREE_MODEL (model), path, &iter);
-	gtk_tree_path_free (path);
+  G_OBJECT_CLASS (ephy_completion_model_parent_class)->finalize (object);
 }
 
 static void
-root_child_changed_cb (EphyNode *node,
-		       EphyNode *child,
-		       guint property_id,
-		       EphyCompletionModel *model)
+ephy_completion_model_class_init (EphyCompletionModelClass *klass)
 {
-	GtkTreePath *path;
-	GtkTreeIter iter;
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
 
-	node_iter_from_node (model, node, child, &iter);
+  object_class->constructed = ephy_completion_model_constructed;
+  object_class->finalize = ephy_completion_model_finalize;
 
-	path = get_path_real (model, node, child);
-	gtk_tree_model_row_changed (GTK_TREE_MODEL (model), path, &iter);
-	gtk_tree_path_free (path);
-}
-
-static void
-connect_signals (EphyCompletionModel *model, EphyNode *root)
-{
-	ephy_node_signal_connect_object (root,
-			                 EPHY_NODE_CHILD_ADDED,
-			                 (EphyNodeCallback)root_child_added_cb,
-			                 G_OBJECT (model));
-	ephy_node_signal_connect_object (root,
-			                 EPHY_NODE_CHILD_REMOVED,
-			                 (EphyNodeCallback)root_child_removed_cb,
-			                 G_OBJECT (model));
-	ephy_node_signal_connect_object (root,
-			                 EPHY_NODE_CHILD_CHANGED,
-			                 (EphyNodeCallback)root_child_changed_cb,
-			                 G_OBJECT (model));
+  g_type_class_add_private (object_class, sizeof (EphyCompletionModelPrivate));
 }
 
 static void
 ephy_completion_model_init (EphyCompletionModel *model)
 {
-	model->priv = EPHY_COMPLETION_MODEL_GET_PRIVATE (model);
-	model->priv->stamp = g_random_int ();
-
-	model->priv->history_service = EPHY_HISTORY (
-					ephy_embed_shell_get_global_history (
-					embed_shell));
-	model->priv->history = ephy_history_get_pages (
-				model->priv->history_service);
-	connect_signals (model, model->priv->history);
-
-	model->priv->bookmarks_service = ephy_shell_get_bookmarks (ephy_shell);
-	model->priv->bookmarks = ephy_bookmarks_get_bookmarks (
-				  model->priv->bookmarks_service);
-	connect_signals (model, model->priv->bookmarks);
-
-	model->priv->favicon_cache = EPHY_FAVICON_CACHE (
-					ephy_embed_shell_get_favicon_cache (
-					EPHY_EMBED_SHELL (ephy_shell)));
-}
-
-EphyCompletionModel *
-ephy_completion_model_new (void)
-{
-	EphyCompletionModel *model;
-
-	model = EPHY_COMPLETION_MODEL (g_object_new (EPHY_TYPE_COMPLETION_MODEL,
-						    NULL));
-
-	g_return_val_if_fail (model->priv != NULL, NULL);
-
-	return model;
-}
-
-static int
-ephy_completion_model_get_n_columns (GtkTreeModel *tree_model)
-{
-	return N_COL;
-}
-
-static GType
-ephy_completion_model_get_column_type (GtkTreeModel *tree_model,
-			               int index)
-{
-	GType type = 0;
-
-	switch (index)
-	{
-		case EPHY_COMPLETION_TEXT_COL:
-		case EPHY_COMPLETION_ACTION_COL:
-		case EPHY_COMPLETION_KEYWORDS_COL:
-			type =  G_TYPE_STRING;
-			break;
-		case EPHY_COMPLETION_EXTRA_COL:
-			type = G_TYPE_BOOLEAN;
-			break;
-		case EPHY_COMPLETION_FAVICON_COL:
-			type = GDK_TYPE_PIXBUF;
-			break;
-		case EPHY_COMPLETION_RELEVANCE_COL:
-			type = G_TYPE_INT;
-			break;
-	}
-
-	return type;
-}
+  EphyCompletionModelPrivate *priv;
+  EphyBookmarks *bookmarks_service;
 
-static void
-init_text_col (GValue *value, EphyNode *node, int group)
-{
-	const char *text;
-
-	switch (group)
-	{
-		case BOOKMARKS_GROUP:
-		case HISTORY_GROUP:
-			text = ephy_node_get_property_string
-				(node, EPHY_NODE_PAGE_PROP_TITLE);
-			break;
-
-		default:
-			text = "";
-	}
-	
-	g_value_set_string (value, text);
-}
+  model->priv = priv = EPHY_COMPLETION_MODEL_GET_PRIVATE (model);
 
-static void
-init_action_col (GValue *value, EphyNode *node)
-{
-	const char *text;
+  priv->browse_history = EPHY_BROWSE_HISTORY (ephy_embed_shell_get_global_browse_history (embed_shell));
+  priv->legacy_history_service = EPHY_HISTORY (ephy_embed_shell_get_global_history (embed_shell));
+  priv->favicon_cache = EPHY_FAVICON_CACHE (ephy_embed_shell_get_favicon_cache (embed_shell));
 
-	text = ephy_node_get_property_string
-		(node, EPHY_NODE_BMK_PROP_LOCATION);
-	
-	g_value_set_string (value, text);
-}
-
-static void
-init_keywords_col (GValue *value, EphyNode *node, int group)
-{
-	const char *text = NULL;
-
-	switch (group)
-	{
-		case BOOKMARKS_GROUP:
-			text = ephy_node_get_property_string
-				(node, EPHY_NODE_BMK_PROP_KEYWORDS);
-			break;
-	}
-
-	if (text == NULL)
-	{
-		text = "";
-	}
-	
-	g_value_set_string (value, text);
-}
-static void
-init_favicon_col (EphyCompletionModel *model, GValue *value, 
-		  EphyNode *node, int group)
-{
-	const char *icon_location;
-	GdkPixbuf *pixbuf = NULL;
-	const char *url;
-
-	switch (group)
-	{
-		case BOOKMARKS_GROUP:
-			icon_location = ephy_node_get_property_string
-				(node, EPHY_NODE_BMK_PROP_ICON);
-			break;
-		case HISTORY_GROUP:
-			url = ephy_node_get_property_string
-				(node, EPHY_NODE_PAGE_PROP_LOCATION);
-			icon_location = ephy_history_get_icon (
-					model->priv->history_service, url);
-			break;
-		default:
-			icon_location = NULL;
-	}
-	
-	if (icon_location)
-	{
-		pixbuf = ephy_favicon_cache_get (
-				model->priv->favicon_cache, icon_location);
-	}
-
-	g_value_take_object (value, pixbuf);
+  bookmarks_service = ephy_shell_get_bookmarks (ephy_shell);
+  priv->bookmarks = ephy_bookmarks_get_bookmarks (bookmarks_service);
 }
 
 static gboolean
 is_base_address (const char *address)
 {
-        if (address == NULL)
-                return FALSE;
-
-        /* a base address is <scheme>://<host>/
-         * Neither scheme nor host contain a slash, so we can use slashes
-         * figure out if it's a base address.
-         *
-         * Note: previous code was using a GRegExp to do the same thing. 
-         * While regexps are much nicer to read, they're also a lot
-         * slower.
-         */
-        address = strchr (address, '/');
-        if (address == NULL ||
-            address[1] != '/')
-                return FALSE;
-
-        address += 2;
-        address = strchr (address, '/');
-        if (address == NULL ||
-            address[1] != 0)
-                return FALSE;
-
-        return TRUE;
+  if (address == NULL)
+    return FALSE;
+
+  /* A base address is <scheme>://<host>/
+   * Neither scheme nor host contain a slash, so we can use slashes
+   * figure out if it's a base address.
+   *
+   * Note: previous code was using a GRegExp to do the same thing. 
+   * While regexps are much nicer to read, they're also a lot
+   * slower.
+   */
+  address = strchr (address, '/');
+  if (address == NULL ||
+      address[1] != '/')
+    return FALSE;
+
+  address += 2;
+  address = strchr (address, '/');
+  if (address == NULL ||
+      address[1] != 0)
+    return FALSE;
+
+  return TRUE;
 }
 
-static void
-init_relevance_col (GValue *value, EphyNode *node, int group)
-{
-	int relevance = 0;
-
-	/* We have three ordered groups: history's base
-	   addresses, bookmarks, deep history addresses */
-
-	if (group == BOOKMARKS_GROUP)
-	{
-		relevance = 1 << 5;
-	}
-	else if (group == HISTORY_GROUP)
-	{
-		const char *address;
-		int visits;
-	
-		visits = ephy_node_get_property_int
-			(node, EPHY_NODE_PAGE_PROP_VISITS);
-		address = ephy_node_get_property_string
-			(node, EPHY_NODE_PAGE_PROP_LOCATION);
-
-		visits = MIN (visits, (1 << 5) - 1);
-
-		if (is_base_address (address))
-		{
-			relevance = visits << 10;
-		}
-		else
-		{
-			relevance = visits;
-		}
-	}
-	
-	g_value_set_int (value, relevance);
+static int
+get_relevance (const char *location,
+               int visit_count,
+               gboolean is_bookmark)
+{
+  /* FIXME: use frecency. */
+  int relevance = 0;
+
+  /* We have three ordered groups: history's base addresses,
+     bookmarks, deep history addresses. */
+  if (is_bookmark)
+    relevance = 1 << 5;
+  else {
+    visit_count = MIN (visit_count, (1 << 5) - 1);
+
+    if (is_base_address (location))
+      relevance = visit_count << 10;
+    else
+      relevance = visit_count;
+  }
+  
+  return relevance;
 }
 
-static void
-init_url_col (GValue *value, EphyNode *node)
-{
-        const char *url = NULL;
-
-	url = ephy_node_get_property_string
-	  (node, EPHY_NODE_PAGE_PROP_LOCATION);
-	
-	g_value_set_string (value, url);
-}
+typedef struct {
+  char *title;
+  char *location;
+  char *keywords;
+  int relevance;
+  gboolean is_bookmark;
+} PotentialRow;
 
 static void
-ephy_completion_model_get_value (GtkTreeModel *tree_model,
-			         GtkTreeIter *iter,
-			         int column,
-			         GValue *value)
-{
-	int group;
-	EphyCompletionModel *model = EPHY_COMPLETION_MODEL (tree_model);
-	EphyNode *node;
-
-	g_return_if_fail (EPHY_IS_COMPLETION_MODEL (tree_model));
-	g_return_if_fail (iter != NULL);
-	g_return_if_fail (iter->stamp == model->priv->stamp);
-
-	node = iter->user_data;
-	group = (iter->user_data2 == model->priv->history) ?
-		HISTORY_GROUP : BOOKMARKS_GROUP;
-
-	switch (column)
-	{
-		case EPHY_COMPLETION_EXTRA_COL:
-			g_value_init (value, G_TYPE_BOOLEAN);
-			g_value_set_boolean (value, (group == BOOKMARKS_GROUP));
-			break;
-		case EPHY_COMPLETION_TEXT_COL:
-			g_value_init (value, G_TYPE_STRING);
-			init_text_col (value, node, group);
-			break;
-		case EPHY_COMPLETION_FAVICON_COL:
-			g_value_init (value, GDK_TYPE_PIXBUF);
-			init_favicon_col (model, value, node, group);
- 			break;
-		case EPHY_COMPLETION_ACTION_COL:
-			g_value_init (value, G_TYPE_STRING);
-			init_action_col (value, node);
-			break;
-		case EPHY_COMPLETION_KEYWORDS_COL:
-			g_value_init (value, G_TYPE_STRING);
-			init_keywords_col (value, node, group);
-			break;
-		case EPHY_COMPLETION_RELEVANCE_COL:
-			g_value_init (value, G_TYPE_INT);
-			init_relevance_col (value, node, group);
-			break;
-                case EPHY_COMPLETION_URL_COL:
-                        g_value_init (value, G_TYPE_STRING);
-                        init_url_col (value, node);
-                        break;
-	}
+set_row_in_model (EphyCompletionModel *model, int position, PotentialRow *row)
+{
+  const char *favicon_location = ephy_history_get_icon (model->priv->legacy_history_service,
+                                                        row->location);
+
+  gtk_list_store_insert_with_values (GTK_LIST_STORE (model), NULL, position,
+                                     EPHY_COMPLETION_TEXT_COL, row->title ? row->title : "",
+                                     EPHY_COMPLETION_URL_COL, row->location,
+                                     EPHY_COMPLETION_ACTION_COL, row->location,
+                                     EPHY_COMPLETION_KEYWORDS_COL, row->keywords ? row->keywords : "",
+                                     EPHY_COMPLETION_EXTRA_COL, row->is_bookmark,
+                                     EPHY_COMPLETION_FAVICON_COL, ephy_favicon_cache_get (model->priv->favicon_cache,
+                                                                                          favicon_location),
+                                     EPHY_COMPLETION_RELEVANCE_COL, row->relevance,
+                                     -1);
 }
 
-static GtkTreeModelFlags
-ephy_completion_model_get_flags (GtkTreeModel *tree_model)
-{
-	return GTK_TREE_MODEL_ITERS_PERSIST | GTK_TREE_MODEL_LIST_ONLY;
+static void
+replace_rows_in_model (EphyCompletionModel *model, GSList *new_rows)
+{
+  /* This is by far the simplest way of doing, and yet it gives
+   * basically the same result than the other methods... */
+  int i;
+
+  gtk_list_store_clear (GTK_LIST_STORE (model));
+
+  for (i = 0; new_rows != NULL; i++) {
+    PotentialRow *row = (PotentialRow*)new_rows->data;
+    
+    set_row_in_model (model, i, row);
+    new_rows = new_rows->next;
+  }
+    
+#if 0
+  int len, n_rows, i;
+  gboolean valid;
+  GtkTreeIter iter;
+
+  len = g_slist_length (new_rows);
+
+  n_rows = 0;
+  valid = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (model), &iter);
+  while (valid) {
+    n_rows++;
+    valid = gtk_tree_model_iter_next (GTK_TREE_MODEL (model), &iter);
+  }
+
+  valid = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (model), &iter);
+
+  while (len < n_rows && n_rows && valid) {
+    valid = gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
+    n_rows--;
+  }
+
+  valid = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (model), &iter);
+  if (!valid)
+    gtk_list_store_append (GTK_LIST_STORE (model), &iter);
+
+  for (i = 0; i < len; i++) {
+    PotentialRow *row = (PotentialRow*)new_rows->data;
+    
+    set_row_in_model (model, &iter, row);
+    new_rows = new_rows->next;
+
+    valid = gtk_tree_model_iter_next (GTK_TREE_MODEL (model), &iter);
+    if (!valid)
+      gtk_list_store_append (GTK_LIST_STORE (model), &iter);
+  }
+#endif
+
+#if 0
+  gboolean valid;
+  GtkTreeIter iter;
+
+  valid = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (model), &iter);
+
+  if (!new_rows)
+    goto delete_rows;
+
+  while (valid) {
+    const char *location;
+    PotentialRow *row = (PotentialRow*)new_rows->data;
+
+    gtk_tree_model_get (GTK_TREE_MODEL (model), &iter,
+                        EPHY_COMPLETION_URL_COL, &location,
+                        -1);
+    if (!g_str_equal (location, row->location))
+      set_row_in_model (model, &iter, row);
+    
+    new_rows = new_rows->next;
+    valid = gtk_tree_model_iter_next (GTK_TREE_MODEL (model), &iter);
+
+    if (!new_rows && valid)
+      goto delete_rows;
+
+    if (!new_rows)
+      break;
+  }
+
+  /* We replaced every row in the model. If there's any new row left,
+   * append them. */
+  while (new_rows) {
+    gtk_list_store_append (GTK_LIST_STORE (model), &iter);
+    
+    set_row_in_model (model, &iter, new_rows->data);
+
+    new_rows = new_rows->next;
+  }
+
+  /* Delete any remaining rows in the model. */
+delete_rows:
+  while (valid)
+    valid = gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
+#endif
 }
 
 static gboolean
-ephy_completion_model_get_iter (GtkTreeModel *tree_model,
-			        GtkTreeIter *iter,
-			        GtkTreePath *path)
-{
-	EphyCompletionModel *model = EPHY_COMPLETION_MODEL (tree_model);
-	EphyNode *root, *child;
-	int i;
-
-	g_return_val_if_fail (EPHY_IS_COMPLETION_MODEL (model), FALSE);
-	g_return_val_if_fail (gtk_tree_path_get_depth (path) > 0, FALSE);
-
-	i = gtk_tree_path_get_indices (path)[0];
-
-	root = get_index_root (model, &i);
-	if (root == NULL) return FALSE;
-
-	child = ephy_node_get_nth_child (root, i);
-	g_return_val_if_fail (child != NULL, FALSE);
-
-	node_iter_from_node (model, root, child, iter);
-
-	return TRUE;
+should_add_bookmark_to_model (EphyCompletionModel *model,
+                              const char *search_string,
+                              const char *title,
+                              const char *location,
+                              const char *keywords)
+{
+  gboolean ret = TRUE;
+  EphyCompletionModelPrivate *priv = model->priv;
+
+  if (priv->search_terms) {
+    GSList *iter;
+    GRegex *current = NULL;
+
+    for (iter = priv->search_terms; iter != NULL; iter = iter->next) {
+      current = (GRegex*) iter->data;
+      if ((!g_regex_match (current, title, G_REGEX_MATCH_NOTEMPTY, NULL)) &&
+          (!g_regex_match (current, location, G_REGEX_MATCH_NOTEMPTY, NULL)) &&
+          (!g_regex_match (current, keywords, G_REGEX_MATCH_NOTEMPTY, NULL))) {
+        ret = FALSE;
+        break;
+      }
+    }
+  }
+
+  return ret;
 }
 
-static GtkTreePath *
-ephy_completion_model_get_path (GtkTreeModel *tree_model,
-			        GtkTreeIter *iter)
-{
-	EphyCompletionModel *model = EPHY_COMPLETION_MODEL (tree_model);
-
-	g_return_val_if_fail (iter != NULL, NULL);
-	g_return_val_if_fail (iter->user_data != NULL, NULL);
-	g_return_val_if_fail (iter->user_data2 != NULL, NULL);
-	g_return_val_if_fail (iter->stamp == model->priv->stamp, NULL);
+typedef struct {
+  EphyCompletionModel *model;
+  char *search_string;
+  EphyHistoryJobCallback callback;
+  gpointer user_data;
+} FindURLsData;
 
-	return get_path_real (model, iter->user_data2, iter->user_data);
+static int
+find_url (gconstpointer a,
+          gconstpointer b)
+{
+  return g_strcmp0 (((PotentialRow*)a)->location,
+                    ((char *)b));
 }
 
-static gboolean
-ephy_completion_model_iter_next (GtkTreeModel *tree_model,
-			         GtkTreeIter *iter)
+static PotentialRow *
+potential_row_new (const char *title, const char *location,
+                   const char *keywords, int visit_count,
+                   gboolean is_bookmark)
 {
-	EphyCompletionModel *model = EPHY_COMPLETION_MODEL (tree_model);
-	EphyNode *node, *next, *root;
-
-	g_return_val_if_fail (iter != NULL, FALSE);
-	g_return_val_if_fail (iter->user_data != NULL, FALSE);
-	g_return_val_if_fail (iter->user_data2 != NULL, FALSE);
-	g_return_val_if_fail (iter->stamp == model->priv->stamp, FALSE);
-
-	node = iter->user_data;
-	root = iter->user_data2;
+  PotentialRow *row = g_slice_new0 (PotentialRow);
 
-	next = ephy_node_get_next_child (root, node);
+  row->title = g_strdup (title);
+  row->location = g_strdup (location);
+  row->keywords = g_strdup (keywords);
+  row->relevance = get_relevance (location, visit_count, is_bookmark);
+  row->is_bookmark = is_bookmark;
 
-	if (next == NULL && root == model->priv->history)
-	{
-		root = model->priv->bookmarks;
-		next = ephy_node_get_nth_child (model->priv->bookmarks, 0);
-	}
-
-	if (next == NULL) return FALSE;
-
-	node_iter_from_node (model, root, next, iter);
-	
-	return TRUE;
+  return row;
 }
 
-static gboolean
-ephy_completion_model_iter_children (GtkTreeModel *tree_model,
-			             GtkTreeIter *iter,
-			             GtkTreeIter *parent)
+static void
+free_potential_row (PotentialRow *row)
 {
-	EphyCompletionModel *model = EPHY_COMPLETION_MODEL (tree_model);
-	EphyNode *root, *first_node;
-
-	if (parent != NULL)
-	{
-		return FALSE;
-	}
-
-	root = model->priv->history;
-	first_node = ephy_node_get_nth_child (root, 0);
-
-	if (first_node == NULL)
-	{
-		root = model->priv->bookmarks;
-		first_node = ephy_node_get_nth_child (root, 0);
-	}
-
-	if (first_node == NULL)
-	{
-		return FALSE;
-	}
-
-	node_iter_from_node (model, root, first_node, iter);
-
-	return TRUE;
+  g_free (row->title);
+  g_free (row->location);
+  g_free (row->keywords);
+  
+  g_slice_free (PotentialRow, row);
 }
 
-static gboolean
-ephy_completion_model_iter_has_child (GtkTreeModel *tree_model,
-			             GtkTreeIter *iter)
-{
-	return FALSE;
+static GSList *
+add_to_potential_rows (GSList *rows,
+                       const char *title,
+                       const char *location,
+                       const char *keywords,
+                       int visit_count,
+                       gboolean is_bookmark,
+                       gboolean search_for_duplicates)
+{
+  gboolean found = FALSE;
+  PotentialRow *row = potential_row_new (title, location, keywords, visit_count, is_bookmark);
+
+  if (search_for_duplicates) {
+    GSList *p;
+
+    p = g_slist_find_custom (rows, location, find_url);
+    if (p) {
+      PotentialRow *match = (PotentialRow*)p->data;
+      if (row->relevance > match->relevance)
+        match->relevance = row->relevance;
+      
+      found = TRUE;
+      free_potential_row (row);
+    }
+  }
+
+  if (!found)
+    rows = g_slist_prepend (rows, row);
+
+  return rows;
 }
 
 static int
-ephy_completion_model_iter_n_children (GtkTreeModel *tree_model,
-			               GtkTreeIter *iter)
+sort_by_relevance (gconstpointer a, gconstpointer b)
 {
-	EphyCompletionModel *model = EPHY_COMPLETION_MODEL (tree_model);
-
-	g_return_val_if_fail (EPHY_IS_COMPLETION_MODEL (tree_model), -1);
-
-	if (iter == NULL)
-	{
-		return ephy_node_get_n_children (model->priv->history) +
-		       ephy_node_get_n_children (model->priv->bookmarks);
-	}
+  PotentialRow *r1 = (PotentialRow*)a;
+  PotentialRow *r2 = (PotentialRow*)b;
 
-	g_return_val_if_fail (model->priv->stamp == iter->stamp, -1);
-
-	return 0;
+  if (r1->relevance < r2->relevance)
+    return 1;
+  else if (r1->relevance > r2->relevance)
+    return -1;
+  else
+    return 0;
 }
 
-static gboolean
-ephy_completion_model_iter_nth_child (GtkTreeModel *tree_model,
-			              GtkTreeIter *iter,
-			              GtkTreeIter *parent,
-			              int n)
-{
-	EphyCompletionModel *model = EPHY_COMPLETION_MODEL (tree_model);
-	EphyNode *node, *root;
-
-	g_return_val_if_fail (EPHY_IS_COMPLETION_MODEL (tree_model), FALSE);
-
-	if (parent != NULL)
-	{
-		return FALSE;
-	}
-
-	root = get_index_root (model, &n);
-	node = ephy_node_get_nth_child (root, n);
-
-	if (node == NULL) return FALSE;
-
-	node_iter_from_node (model, root, node, iter);
+static void
+query_completed_cb (EphyHistoryService *service,
+                    gboolean success,
+                    gpointer result_data,
+                    FindURLsData *user_data)
+{
+  EphyCompletionModel *model = user_data->model;
+  EphyCompletionModelPrivate *priv = model->priv;
+  GList *p, *urls;
+  GPtrArray *children;
+  GSList *list = NULL;
+  int i;
+
+  /* Bookmarks */
+  children = ephy_node_get_children (priv->bookmarks);
+
+  /* FIXME: perhaps this could be done in a service thread? There
+   * should never be a ton of bookmarks, but seems a bit cleaner and
+   * consistent with what we do for the history. */
+  for (i = 0; i < children->len; i++) {
+    EphyNode *kid;
+    const char *keywords, *location, *title;
+
+    kid = g_ptr_array_index (children, i);
+    location = ephy_node_get_property_string (kid, EPHY_NODE_BMK_PROP_LOCATION);
+    title = ephy_node_get_property_string (kid, EPHY_NODE_BMK_PROP_TITLE);
+    keywords = ephy_node_get_property_string (kid, EPHY_NODE_BMK_PROP_KEYWORDS);
+
+    if (should_add_bookmark_to_model (model, user_data->search_string,
+                                      title, location, keywords))
+      list = add_to_potential_rows (list, title, location, keywords, 0, TRUE, FALSE);
+  }
+
+  /* History */
+  urls = (GList*)result_data;
+
+  for (p = urls; p != NULL; p = p->next) {
+    EphyHistoryURL *url = (EphyHistoryURL*)p->data;
+
+    list = add_to_potential_rows (list, url->title, url->url, NULL, url->visit_count, FALSE, TRUE);
+  }
+
+  /* Sort the rows by relevance. */
+  list = g_slist_sort (list, sort_by_relevance);
+
+  /* Now that we have all the rows we want to insert, replace the rows
+   * in the current model one by one, sorted by relevance. */
+  replace_rows_in_model (model, list);
+
+  /* Notify */
+  if (user_data->callback)
+    user_data->callback (service, success, result_data, user_data->user_data);
+
+  g_free (user_data->search_string);
+  g_slice_free (FindURLsData, user_data);
+
+  g_slist_free_full (list, (GDestroyNotify)free_potential_row);
+}
 
-	return TRUE;
+static void
+update_search_terms (EphyCompletionModel *model,
+                     const char *text)
+{
+  const char *current;
+  const char *ptr;
+  char *tmp;
+  char *term;
+  GRegex *term_regex;
+  GRegex *quote_regex;
+  gint count;
+  gboolean inside_quotes = FALSE;
+  EphyCompletionModelPrivate *priv = model->priv;
+
+  if (priv->search_terms) {
+    free_search_terms (priv->search_terms);
+    priv->search_terms = NULL;
+  }
+
+  quote_regex = g_regex_new ("\"", G_REGEX_OPTIMIZE,
+                             G_REGEX_MATCH_NOTEMPTY, NULL);
+    
+  /*
+   * This code loops through the string using pointer arythmetics.
+   * Although the string we are handling may contain UTF-8 chars
+   * this works because only ASCII chars affect what is actually
+   * copied from the string as a search term.
+   */
+  for (count = 0, current = ptr = text; ptr[0] != '\0'; ptr++, count++) {
+    /*
+     * If we found a double quote character; we will 
+     * consume bytes up until the next quote, or
+     * end of line;
+     */
+    if (ptr[0] == '"')
+      inside_quotes = !inside_quotes;
+
+    /*
+     * If we found a space, and we are not looking for a
+     * closing double quote, or if the next char is the
+     * end of the string, append what we have already as
+     * a search term.
+     */
+    if (((ptr[0] == ' ') && (!inside_quotes)) || ptr[1] == '\0') {
+      /*
+       * We special-case the end of the line because
+       * we would otherwise not copy the last character
+       * of the search string, since the for loop will
+       * stop before that.
+       */
+      if (ptr[1] == '\0')
+        count++;
+        
+      /*
+       * remove quotes, and quote any regex-sensitive
+       * characters
+       */
+      tmp = g_regex_escape_string (current, count);
+      term = g_regex_replace (quote_regex, tmp, -1, 0,
+                              "", G_REGEX_MATCH_NOTEMPTY, NULL);
+      g_strstrip (term);
+      g_free (tmp);
+
+      /* we don't want empty search terms */
+      if (term[0] != '\0') {
+        term_regex = g_regex_new (term,
+                                  G_REGEX_CASELESS | G_REGEX_OPTIMIZE,
+                                  G_REGEX_MATCH_NOTEMPTY, NULL);
+        priv->search_terms = g_slist_append (priv->search_terms, term_regex);
+      }
+      g_free (term);
+
+      /* count will be incremented by the for loop */
+      count = -1;
+      current = ptr + 1;
+    }
+  }
+
+  g_regex_unref (quote_regex);
 }
 
-static gboolean
-ephy_completion_model_iter_parent (GtkTreeModel *tree_model,
-			           GtkTreeIter *iter,
-			           GtkTreeIter *child)
-{
-	return FALSE;
+#define MAX_COMPLETION_HISTORY_URLS 8
+
+void
+ephy_completion_model_update_for_string (EphyCompletionModel *model,
+                                         const char *search_string,
+                                         EphyHistoryJobCallback callback,
+                                         gpointer data)
+{
+  EphyCompletionModelPrivate *priv;
+  char **strings;
+  int i;
+  GList *query = NULL;
+  FindURLsData *user_data;
+
+  g_return_if_fail (EPHY_IS_COMPLETION_MODEL (model));
+  g_return_if_fail (search_string != NULL);
+
+  priv = model->priv;
+
+  /* Split the search string. */
+  strings = g_strsplit (search_string, " ", -1);
+  for (i = 0; strings[i]; i++)
+    query = g_list_append (query, g_strdup (strings[i]));
+  g_strfreev (strings);
+
+  update_search_terms (model, search_string);
+
+  user_data = g_slice_new (FindURLsData);
+  user_data->model = model;
+  user_data->search_string = g_strdup (search_string);
+  user_data->callback = callback;
+  user_data->user_data = data;
+
+  ephy_browse_history_find_urls (priv->browse_history,
+                                 0, 0,
+                                 MAX_COMPLETION_HISTORY_URLS,
+                                 query,
+                                 (EphyHistoryJobCallback)query_completed_cb,
+                                 user_data);
 }
 
-static void
-ephy_completion_model_tree_model_init (GtkTreeModelIface *iface)
+EphyCompletionModel *
+ephy_completion_model_new (void)
 {
-	iface->get_flags       = ephy_completion_model_get_flags;
-	iface->get_iter        = ephy_completion_model_get_iter;
-	iface->get_path        = ephy_completion_model_get_path;
-	iface->iter_next       = ephy_completion_model_iter_next;
-	iface->iter_children   = ephy_completion_model_iter_children;
-	iface->iter_has_child  = ephy_completion_model_iter_has_child;
-	iface->iter_n_children = ephy_completion_model_iter_n_children;
-	iface->iter_nth_child  = ephy_completion_model_iter_nth_child;
-	iface->iter_parent     = ephy_completion_model_iter_parent;
-	iface->get_n_columns   = ephy_completion_model_get_n_columns;
-	iface->get_column_type = ephy_completion_model_get_column_type;
-	iface->get_value       = ephy_completion_model_get_value;
+  return g_object_new (EPHY_TYPE_COMPLETION_MODEL, NULL);
 }
diff --git a/src/ephy-completion-model.h b/src/ephy-completion-model.h
index 62cae95..f02f812 100644
--- a/src/ephy-completion-model.h
+++ b/src/ephy-completion-model.h
@@ -1,5 +1,5 @@
 /*
- *  Copyright  2003 Marco Pesenti Gritti <marco gnome org>
+ *  Copyright  2012 Igalia S.L.
  *
  *  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
@@ -24,6 +24,8 @@
 #ifndef EPHY_COMPLETION_MODEL_H
 #define EPHY_COMPLETION_MODEL_H
 
+#include "ephy-history-service.h"
+
 #include <gtk/gtk.h>
 
 G_BEGIN_DECLS
@@ -51,7 +53,7 @@ typedef enum
 
 typedef struct
 {
-	GObject parent;
+	GtkListStore parent;
 
 	/*< private >*/
 	EphyCompletionModelPrivate *priv;
@@ -59,13 +61,17 @@ typedef struct
 
 typedef struct
 {
-	GObjectClass parent;
+	GtkListStoreClass parent;
 } EphyCompletionModelClass;
 
-GType                ephy_completion_model_get_type	(void);
+GType                ephy_completion_model_get_type	     (void);
 
-EphyCompletionModel *ephy_completion_model_new		(void);
+EphyCompletionModel *ephy_completion_model_new		     (void);
 
+void                 ephy_completion_model_update_for_string (EphyCompletionModel *model,
+                                                              const char *string,
+                                                              EphyHistoryJobCallback callback,
+                                                              gpointer data);
 G_END_DECLS
 
 #endif /* EPHY_COMPLETION_MODEL_H */
diff --git a/src/ephy-location-controller.c b/src/ephy-location-controller.c
index b0509dd..9315ad6 100644
--- a/src/ephy-location-controller.c
+++ b/src/ephy-location-controller.c
@@ -96,51 +96,8 @@ match_func (GtkEntryCompletion *completion,
 	    GtkTreeIter *iter,
 	    gpointer data)
 {
-	char *item = NULL;
-	char *url = NULL;
-	char *keywords = NULL;
-
-	gboolean ret = FALSE;
-	GtkTreeModel *model;
-	GSList *search_terms;
-
-	model = gtk_entry_completion_get_model (completion);
-
-	gtk_tree_model_get (model, iter,
-			    EPHY_COMPLETION_TEXT_COL, &item,
-			    EPHY_COMPLETION_URL_COL, &url,
-			    EPHY_COMPLETION_KEYWORDS_COL, &keywords,
-			    -1);
-	
-	if (!key)
-		return FALSE;
-	
-	search_terms = ephy_location_entry_get_search_terms (data);
-
-	if (search_terms)
-	{
-		GSList *iter;
-		GRegex *current = NULL;
-
-		ret = TRUE;
-		for (iter = search_terms; iter != NULL; iter = iter->next)
-		{
-			current = (GRegex*) iter->data;
-			if ((!g_regex_match (current, item, G_REGEX_MATCH_NOTEMPTY, NULL)) &&
-			    (!g_regex_match (current, url, G_REGEX_MATCH_NOTEMPTY, NULL)) &&
-			    (!g_regex_match (current, keywords, G_REGEX_MATCH_NOTEMPTY, NULL)))
-			{
-				ret = FALSE;
-				break;
-			}
-		}
-	}
-
-	g_free (item);
-	g_free (url);
-	g_free (keywords);
-
-	return ret;
+	/* We want every row in the model to show up. */
+	return TRUE;
 }
 
 static void
@@ -211,6 +168,8 @@ static void
 user_changed_cb (GtkWidget *widget, EphyLocationController *controller)
 {
 	const char *address;
+	GtkTreeModel *model;
+	GtkEntryCompletion *completion;
 
 	address = ephy_location_entry_get_location (EPHY_LOCATION_ENTRY (widget));
 
@@ -218,6 +177,12 @@ user_changed_cb (GtkWidget *widget, EphyLocationController *controller)
 
 	g_signal_handlers_block_by_func (controller, G_CALLBACK (sync_address), widget);
 	ephy_location_controller_set_address (controller, address);
+
+	completion = gtk_entry_get_completion (GTK_ENTRY (widget));
+	model = gtk_entry_completion_get_model (completion);
+
+	ephy_completion_model_update_for_string (EPHY_COMPLETION_MODEL (model), address,
+						 NULL, NULL);
 	g_signal_handlers_unblock_by_func (controller, G_CALLBACK (sync_address), widget);
 }
 
@@ -428,7 +393,7 @@ ephy_location_controller_constructed (GObject *object)
 					    EPHY_COMPLETION_EXTRA_COL,
 					    EPHY_COMPLETION_FAVICON_COL);
 	g_object_unref (model);
-		
+
 	ephy_location_entry_set_match_func (priv->location_entry, 
 					    match_func, 
 					    priv->location_entry,



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