[nautilus] Add an experimental search provider that pulls from the directory model



commit 3d046cfc17bb36e65a322e53d263fe8bcdc2762c
Author: William Jon McCann <jmccann redhat com>
Date:   Wed Sep 5 21:23:52 2012 -0400

    Add an experimental search provider that pulls from the directory model

 libnautilus-private/Makefile.am                    |    2 +
 libnautilus-private/nautilus-search-engine-model.c |  403 ++++++++++++++++++++
 libnautilus-private/nautilus-search-engine-model.h |   51 +++
 libnautilus-private/nautilus-search-engine.c       |   30 ++-
 4 files changed, 485 insertions(+), 1 deletions(-)
---
diff --git a/libnautilus-private/Makefile.am b/libnautilus-private/Makefile.am
index cdd481f..95c4219 100644
--- a/libnautilus-private/Makefile.am
+++ b/libnautilus-private/Makefile.am
@@ -162,6 +162,8 @@ libnautilus_private_la_SOURCES = \
 	nautilus-search-provider.h \
 	nautilus-search-engine.c \
 	nautilus-search-engine.h \
+	nautilus-search-engine-model.c \
+	nautilus-search-engine-model.h \
 	nautilus-search-engine-simple.c \
 	nautilus-search-engine-simple.h \
 	nautilus-search-hit.c \
diff --git a/libnautilus-private/nautilus-search-engine-model.c b/libnautilus-private/nautilus-search-engine-model.c
new file mode 100644
index 0000000..4c1144c
--- /dev/null
+++ b/libnautilus-private/nautilus-search-engine-model.c
@@ -0,0 +1,403 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/*
+ * Copyright (C) 2005 Red Hat, Inc
+ *
+ * Nautilus 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.
+ *
+ * Nautilus 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; see the file COPYING.  If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Alexander Larsson <alexl redhat com>
+ *
+ */
+
+#include <config.h>
+#include "nautilus-search-hit.h"
+#include "nautilus-search-provider.h"
+#include "nautilus-search-engine-model.h"
+#include "nautilus-directory.h"
+#include "nautilus-directory-private.h"
+#include "nautilus-file.h"
+
+#include <string.h>
+#include <glib.h>
+#include <gio/gio.h>
+
+#define BATCH_SIZE 500
+
+typedef struct {
+	NautilusSearchEngineModel *engine;
+	GCancellable *cancellable;
+
+	GList *mime_types;
+	char **words;
+	GList *found_list;
+
+	GQueue *directories; /* GFiles */
+
+	GHashTable *visited;
+
+	gint n_processed_files;
+	GList *hits;
+} SearchData;
+
+
+struct NautilusSearchEngineModelDetails {
+	NautilusQuery *query;
+
+	SearchData *active_search;
+
+	gboolean query_finished;
+};
+
+static void nautilus_search_provider_init (NautilusSearchProviderIface  *iface);
+
+G_DEFINE_TYPE_WITH_CODE (NautilusSearchEngineModel,
+			 nautilus_search_engine_model,
+			 G_TYPE_OBJECT,
+			 G_IMPLEMENT_INTERFACE (NAUTILUS_TYPE_SEARCH_PROVIDER,
+						nautilus_search_provider_init))
+
+static void
+finalize (GObject *object)
+{
+	NautilusSearchEngineModel *model;
+
+	model = NAUTILUS_SEARCH_ENGINE_MODEL (object);
+
+	if (model->details->query) {
+		g_object_unref (model->details->query);
+		model->details->query = NULL;
+	}
+
+	G_OBJECT_CLASS (nautilus_search_engine_model_parent_class)->finalize (object);
+}
+
+static SearchData *
+search_data_new (NautilusSearchEngineModel *engine,
+		 NautilusQuery *query)
+{
+	SearchData *data;
+	char *text, *lower, *normalized, *uri;
+	GFile *location;
+
+	data = g_new0 (SearchData, 1);
+
+	data->engine = g_object_ref (engine);
+	data->directories = g_queue_new ();
+	data->visited = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+	uri = nautilus_query_get_location (query);
+	location = NULL;
+	if (uri != NULL) {
+		location = g_file_new_for_uri (uri);
+		g_free (uri);
+	}
+	if (location == NULL) {
+		location = g_file_new_for_path ("/");
+	}
+	g_queue_push_tail (data->directories, location);
+
+	text = nautilus_query_get_text (query);
+	g_message ("text %s", text);
+	normalized = g_utf8_normalize (text, -1, G_NORMALIZE_NFD);
+	lower = g_utf8_strdown (normalized, -1);
+	data->words = g_strsplit (lower, " ", -1);
+	g_free (text);
+	g_free (lower);
+	g_free (normalized);
+
+	data->mime_types = nautilus_query_get_mime_types (query);
+
+	data->cancellable = g_cancellable_new ();
+
+	return data;
+}
+
+static void
+search_data_free (SearchData *data)
+{
+	g_queue_foreach (data->directories,
+			 (GFunc)g_object_unref, NULL);
+	g_queue_free (data->directories);
+	g_hash_table_destroy (data->visited);
+	g_object_unref (data->cancellable);
+	g_strfreev (data->words);
+	g_list_free_full (data->mime_types, g_free);
+	g_list_free_full (data->hits, g_object_unref);
+	g_object_unref (data->engine);
+
+	g_free (data);
+}
+
+static gboolean
+search_done_idle (gpointer user_data)
+{
+	SearchData *data = user_data;
+
+	if (!g_cancellable_is_cancelled (data->cancellable)) {
+		nautilus_search_provider_finished (NAUTILUS_SEARCH_PROVIDER (data->engine));
+		data->engine->details->active_search = NULL;
+	}
+
+	search_data_free (data);
+
+	return FALSE;
+}
+
+typedef struct {
+	GList *hits;
+	SearchData *thread_data;
+} SearchHitsData;
+
+static gboolean
+search_add_hits_idle (gpointer user_data)
+{
+	SearchHitsData *data = user_data;
+
+	if (!g_cancellable_is_cancelled (data->thread_data->cancellable)) {
+		nautilus_search_provider_hits_added (NAUTILUS_SEARCH_PROVIDER (data->thread_data->engine),
+						     data->hits);
+	}
+
+	g_list_free_full (data->hits, g_object_unref);
+	g_free (data);
+
+	return FALSE;
+}
+
+static void
+send_batch (SearchData *thread_data)
+{
+	SearchHitsData *data;
+
+	thread_data->n_processed_files = 0;
+
+	if (thread_data->hits) {
+		data = g_new (SearchHitsData, 1);
+		data->hits = thread_data->hits;
+		data->thread_data = thread_data;
+		g_idle_add (search_add_hits_idle, data);
+	}
+	thread_data->hits = NULL;
+}
+
+static void
+got_files_callback (NautilusDirectory *directory,
+		    GList             *files,
+		    SearchData        *data)
+{
+	GList *node;
+
+	for (node = files; node != NULL; node = node->next) {
+		NautilusFile *file = node->data;
+		char *display_name;
+		char *normalized;
+		char *lower_name;
+		gboolean found;
+		int i;
+
+		display_name = nautilus_file_get_display_name (file);
+		g_message ("got %s", display_name);
+		if (display_name == NULL) {
+			continue;
+		}
+
+		normalized = g_utf8_normalize (display_name, -1, G_NORMALIZE_NFD);
+		lower_name = g_utf8_strdown (normalized, -1);
+		g_free (normalized);
+
+		found = TRUE;
+		for (i = 0; data->words[i] != NULL; i++) {
+			if (strstr (lower_name, data->words[i]) == NULL) {
+				found = FALSE;
+				break;
+			}
+		}
+		g_free (lower_name);
+
+		if (found && data->mime_types) {
+			GList *l;
+
+			found = FALSE;
+
+			for (l = data->mime_types; l != NULL; l = l->next) {
+				if (nautilus_file_is_mime_type (file, l->data)) {
+					found = TRUE;
+					break;
+				}
+			}
+		}
+
+		if (found) {
+			NautilusSearchHit *hit;
+			GDateTime *dt;
+			char *uri;
+			time_t t;
+
+			uri = nautilus_file_get_uri (file);
+			hit = nautilus_search_hit_new (uri);
+			g_message ("FOUND %s", uri);
+			g_free (uri);
+			nautilus_search_hit_set_fts_rank (hit, 10.0);
+			t = nautilus_file_get_mtime (file);
+			dt = g_date_time_new_from_unix_local (t);
+			nautilus_search_hit_set_modification_time (hit, dt);
+			g_date_time_unref (dt);
+
+			data->hits = g_list_prepend (data->hits, hit);
+		}
+
+		data->n_processed_files++;
+		if (data->n_processed_files > BATCH_SIZE) {
+			send_batch (data);
+		}
+	}
+	send_batch (data);
+	g_idle_add (search_done_idle, data);
+}
+
+static void
+visit_directory (GFile *dir, SearchData *data)
+{
+	NautilusDirectory *directory;
+
+	g_message ("searching %s", g_file_get_uri (dir));
+	directory = nautilus_directory_get (dir);
+	nautilus_directory_call_when_ready (directory,
+					    NAUTILUS_FILE_ATTRIBUTE_INFO,
+					    TRUE,
+					    (NautilusDirectoryCallback)got_files_callback,
+					    data);
+	g_object_unref (directory);
+}
+
+static gpointer
+search_thread_func (gpointer user_data)
+{
+	SearchData *data = user_data;
+	GFile *dir;
+	GFileInfo *info;
+	const char *id;
+
+	/* Insert id for toplevel directory into visited */
+	dir = g_queue_peek_head (data->directories);
+	info = g_file_query_info (dir, G_FILE_ATTRIBUTE_ID_FILE, 0, data->cancellable, NULL);
+	if (info) {
+		id = g_file_info_get_attribute_string (info, G_FILE_ATTRIBUTE_ID_FILE);
+		if (id) {
+			g_hash_table_insert (data->visited, g_strdup (id), NULL);
+		}
+		g_object_unref (info);
+	}
+
+	while (!g_cancellable_is_cancelled (data->cancellable) &&
+	       (dir = g_queue_pop_head (data->directories)) != NULL) {
+		visit_directory (dir, data);
+		g_object_unref (dir);
+	}
+
+	return NULL;
+}
+
+static void
+nautilus_search_engine_model_start (NautilusSearchProvider *provider)
+{
+	NautilusSearchEngineModel *model;
+	SearchData *data;
+	GThread *thread;
+
+	model = NAUTILUS_SEARCH_ENGINE_MODEL (provider);
+
+	if (model->details->active_search != NULL) {
+		return;
+	}
+
+	if (model->details->query == NULL) {
+		return;
+	}
+
+	data = search_data_new (model, model->details->query);
+
+	thread = g_thread_new ("nautilus-search-model", search_thread_func, data);
+	model->details->active_search = data;
+
+	g_thread_unref (thread);
+}
+
+static void
+nautilus_search_engine_model_stop (NautilusSearchProvider *provider)
+{
+	NautilusSearchEngineModel *model;
+
+	model = NAUTILUS_SEARCH_ENGINE_MODEL (provider);
+
+	if (model->details->active_search != NULL) {
+		g_cancellable_cancel (model->details->active_search->cancellable);
+		model->details->active_search = NULL;
+	}
+}
+
+static void
+nautilus_search_engine_model_set_query (NautilusSearchProvider *provider,
+					 NautilusQuery          *query)
+{
+	NautilusSearchEngineModel *model;
+
+	model = NAUTILUS_SEARCH_ENGINE_MODEL (provider);
+
+	if (query) {
+		g_object_ref (query);
+	}
+
+	if (model->details->query) {
+		g_object_unref (model->details->query);
+	}
+
+	model->details->query = query;
+}
+
+static void
+nautilus_search_provider_init (NautilusSearchProviderIface *iface)
+{
+	iface->set_query = nautilus_search_engine_model_set_query;
+	iface->start = nautilus_search_engine_model_start;
+	iface->stop = nautilus_search_engine_model_stop;
+}
+
+static void
+nautilus_search_engine_model_class_init (NautilusSearchEngineModelClass *class)
+{
+	GObjectClass *gobject_class;
+
+	gobject_class = G_OBJECT_CLASS (class);
+	gobject_class->finalize = finalize;
+
+	g_type_class_add_private (class, sizeof (NautilusSearchEngineModelDetails));
+}
+
+static void
+nautilus_search_engine_model_init (NautilusSearchEngineModel *engine)
+{
+	engine->details = G_TYPE_INSTANCE_GET_PRIVATE (engine, NAUTILUS_TYPE_SEARCH_ENGINE_MODEL,
+						       NautilusSearchEngineModelDetails);
+}
+
+NautilusSearchEngineModel *
+nautilus_search_engine_model_new (void)
+{
+	NautilusSearchEngineModel *engine;
+
+	engine = g_object_new (NAUTILUS_TYPE_SEARCH_ENGINE_MODEL, NULL);
+
+	return engine;
+}
diff --git a/libnautilus-private/nautilus-search-engine-model.h b/libnautilus-private/nautilus-search-engine-model.h
new file mode 100644
index 0000000..1a2d0ae
--- /dev/null
+++ b/libnautilus-private/nautilus-search-engine-model.h
@@ -0,0 +1,51 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/*
+ * Copyright (C) 2005 Red Hat, Inc
+ *
+ * Nautilus 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.
+ *
+ * Nautilus 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; see the file COPYING.  If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Alexander Larsson <alexl redhat com>
+ *
+ */
+
+#ifndef NAUTILUS_SEARCH_ENGINE_MODEL_H
+#define NAUTILUS_SEARCH_ENGINE_MODEL_H
+
+#include <libnautilus-private/nautilus-search-engine.h>
+
+#define NAUTILUS_TYPE_SEARCH_ENGINE_MODEL		(nautilus_search_engine_model_get_type ())
+#define NAUTILUS_SEARCH_ENGINE_MODEL(obj)		(G_TYPE_CHECK_INSTANCE_CAST ((obj), NAUTILUS_TYPE_SEARCH_ENGINE_MODEL, NautilusSearchEngineModel))
+#define NAUTILUS_SEARCH_ENGINE_MODEL_CLASS(klass)	(G_TYPE_CHECK_CLASS_CAST ((klass), NAUTILUS_TYPE_SEARCH_ENGINE_MODEL, NautilusSearchEngineModelClass))
+#define NAUTILUS_IS_SEARCH_ENGINE_MODEL(obj)		(G_TYPE_CHECK_INSTANCE_TYPE ((obj), NAUTILUS_TYPE_SEARCH_ENGINE_MODEL))
+#define NAUTILUS_IS_SEARCH_ENGINE_MODEL_CLASS(klass)	(G_TYPE_CHECK_CLASS_TYPE ((klass), NAUTILUS_TYPE_SEARCH_ENGINE_MODEL))
+#define NAUTILUS_SEARCH_ENGINE_MODEL_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), NAUTILUS_TYPE_SEARCH_ENGINE_MODEL, NautilusSearchEngineModelClass))
+
+typedef struct NautilusSearchEngineModelDetails NautilusSearchEngineModelDetails;
+
+typedef struct NautilusSearchEngineModel {
+	GObject parent;
+	NautilusSearchEngineModelDetails *details;
+} NautilusSearchEngineModel;
+
+typedef struct {
+	GObjectClass parent_class;
+} NautilusSearchEngineModelClass;
+
+GType          nautilus_search_engine_model_get_type  (void);
+
+NautilusSearchEngineModel* nautilus_search_engine_model_new       (void);
+
+#endif /* NAUTILUS_SEARCH_ENGINE_MODEL_H */
diff --git a/libnautilus-private/nautilus-search-engine.c b/libnautilus-private/nautilus-search-engine.c
index fc84729..0f1d38d 100644
--- a/libnautilus-private/nautilus-search-engine.c
+++ b/libnautilus-private/nautilus-search-engine.c
@@ -27,16 +27,23 @@
 #include "nautilus-search-provider.h"
 #include "nautilus-search-engine.h"
 #include "nautilus-search-engine-simple.h"
+#include "nautilus-search-engine-model.h"
 #define DEBUG_FLAG NAUTILUS_DEBUG_SEARCH
 #include "nautilus-debug.h"
 
+#undef ENABLE_TRACKER
+
 #ifdef ENABLE_TRACKER
 #include "nautilus-search-engine-tracker.h"
 #endif
 
 struct NautilusSearchEngineDetails
 {
+#if USE_MODEL
+	NautilusSearchEngineModel *model;
+#else
 	NautilusSearchEngineSimple *simple;
+#endif
 #ifdef ENABLE_TRACKER
 	NautilusSearchEngineTracker *tracker;
 #endif
@@ -62,7 +69,11 @@ nautilus_search_engine_set_query (NautilusSearchProvider *provider,
 #ifdef ENABLE_TRACKER
 	nautilus_search_provider_set_query (NAUTILUS_SEARCH_PROVIDER (engine->details->tracker), query);
 #endif
+#if USE_MODEL
+	nautilus_search_provider_set_query (NAUTILUS_SEARCH_PROVIDER (engine->details->model), query);
+#else
 	nautilus_search_provider_set_query (NAUTILUS_SEARCH_PROVIDER (engine->details->simple), query);
+#endif
 }
 
 static void
@@ -74,7 +85,11 @@ nautilus_search_engine_start (NautilusSearchProvider *provider)
 #ifdef ENABLE_TRACKER
 	nautilus_search_provider_start (NAUTILUS_SEARCH_PROVIDER (engine->details->tracker));
 #endif
+#if USE_MODEL
+	nautilus_search_provider_start (NAUTILUS_SEARCH_PROVIDER (engine->details->model));
+#else
 	nautilus_search_provider_start (NAUTILUS_SEARCH_PROVIDER (engine->details->simple));
+#endif
 }
 
 static void
@@ -84,7 +99,11 @@ nautilus_search_engine_stop (NautilusSearchProvider *provider)
 #ifdef ENABLE_TRACKER
 	nautilus_search_provider_stop (NAUTILUS_SEARCH_PROVIDER (engine->details->tracker));
 #endif
+#if USE_MODEL
+	nautilus_search_provider_stop (NAUTILUS_SEARCH_PROVIDER (engine->details->model));
+#else
 	nautilus_search_provider_stop (NAUTILUS_SEARCH_PROVIDER (engine->details->simple));
+#endif
 }
 
 static void
@@ -209,7 +228,11 @@ nautilus_search_engine_finalize (GObject *object)
 #ifdef ENABLE_TRACKER
 	g_clear_object (&engine->details->tracker);
 #endif
+#if USE_MODEL
+	g_clear_object (&engine->details->model);
+#else
 	g_clear_object (&engine->details->simple);
+#endif
 
 	G_OBJECT_CLASS (nautilus_search_engine_parent_class)->finalize (object);
 }
@@ -240,10 +263,15 @@ nautilus_search_engine_init (NautilusSearchEngine *engine)
 	connect_provider_signals (engine, NAUTILUS_SEARCH_PROVIDER (engine->details->tracker));
 	engine->details->num_providers++;
 #endif
-
+#if USE_MODEL
+	engine->details->model = nautilus_search_engine_model_new ();
+	connect_provider_signals (engine, NAUTILUS_SEARCH_PROVIDER (engine->details->model));
+	engine->details->num_providers++;
+#else
 	engine->details->simple = nautilus_search_engine_simple_new ();
 	connect_provider_signals (engine, NAUTILUS_SEARCH_PROVIDER (engine->details->simple));
 	engine->details->num_providers++;
+#endif
 }
 
 NautilusSearchEngine *



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