[grilo-plugins] filesystem: implemented search
- From: Iago Toral Quiroga <itoral src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [grilo-plugins] filesystem: implemented search
- Date: Tue, 18 Jan 2011 07:50:23 +0000 (UTC)
commit 8b6c7a053f728737ae6595b8862ca2b6ef998999
Author: Guillaume Emont <gemont igalia com>
Date: Wed Jan 12 18:47:09 2011 +0100
filesystem: implemented search
Fixes https://bugzilla.gnome.org/show_bug.cgi?id=639345
Signed-off-by: Iago Toral Quiroga <itoral igalia com>
src/filesystem/grl-filesystem.c | 252 +++++++++++++++++++++++++++++++++++++++
1 files changed, 252 insertions(+), 0 deletions(-)
---
diff --git a/src/filesystem/grl-filesystem.c b/src/filesystem/grl-filesystem.c
index 29d415d..dce85b4 100644
--- a/src/filesystem/grl-filesystem.c
+++ b/src/filesystem/grl-filesystem.c
@@ -87,6 +87,15 @@ typedef struct {
guint remaining;
} BrowseIdleData;
+/* probably not thread-safe */
+typedef struct {
+ GrlMediaSource *source;
+ GrlMediaSourceSearchSpec *ss;
+ guint found_count;
+ guint skipped;
+ GQueue *directories;
+} SearchOperation;
+
static GrlFilesystemSource *grl_filesystem_source_new (void);
static void grl_filesystem_source_finalize (GObject *object);
@@ -103,6 +112,10 @@ static void grl_filesystem_source_metadata (GrlMediaSource *source,
static void grl_filesystem_source_browse (GrlMediaSource *source,
GrlMediaSourceBrowseSpec *bs);
+static void grl_filesystem_source_search (GrlMediaSource *source,
+ GrlMediaSourceSearchSpec *ss);
+
+
static gboolean grl_filesystem_test_media_from_uri (GrlMediaSource *source,
const gchar *uri);
@@ -171,6 +184,7 @@ grl_filesystem_source_class_init (GrlFilesystemSourceClass * klass)
GrlMediaSourceClass *source_class = GRL_MEDIA_SOURCE_CLASS (klass);
GrlMetadataSourceClass *metadata_class = GRL_METADATA_SOURCE_CLASS (klass);
source_class->browse = grl_filesystem_source_browse;
+ source_class->search = grl_filesystem_source_search;
source_class->metadata = grl_filesystem_source_metadata;
source_class->test_media_from_uri = grl_filesystem_test_media_from_uri;
source_class->media_from_uri = grl_filesystem_get_media_from_uri;
@@ -559,6 +573,216 @@ produce_from_path (GrlMediaSourceBrowseSpec *bs, const gchar *path)
g_dir_close (dir);
}
+/*** search stuff ***/
+
+static void search_next_directory (SearchOperation *operation);
+
+static SearchOperation *
+search_operation_new (GrlMediaSource *source, GrlMediaSourceSearchSpec *ss)
+{
+ SearchOperation *operation;
+
+ operation = g_new (SearchOperation, 1);
+ operation->source = source;
+ operation->ss = ss;
+ operation->found_count = 0;
+ operation->skipped = 0;
+ operation->directories = g_queue_new ();
+
+ return operation;
+}
+
+static void
+search_operation_free (SearchOperation *operation)
+{
+ g_queue_foreach (operation->directories, (GFunc)g_object_unref, NULL);
+ g_queue_free (operation->directories);
+ g_free (operation);
+}
+
+/* return TRUE if more files need to be returned, FALSE if we sent the count */
+static gboolean
+compare_and_return_file (SearchOperation *operation,
+ GFileEnumerator *enumerator,
+ GFileInfo *file_info)
+{
+ gchar *needle, *haystack, *normalized_needle, *normalized_haystack;
+ GrlMediaSourceSearchSpec *ss = operation->ss;
+
+ GRL_DEBUG ("compare_and_return_file");
+
+ if (ss == NULL)
+ return FALSE;
+
+ haystack = g_utf8_casefold (g_file_info_get_display_name (file_info), -1);
+ normalized_haystack = g_utf8_normalize (haystack, -1, G_NORMALIZE_ALL);
+
+ needle = g_utf8_casefold (ss->text, -1);
+ normalized_needle = g_utf8_normalize (needle, -1, G_NORMALIZE_ALL);
+
+ if (strstr (normalized_haystack, normalized_needle)) {
+ GrlMedia *media = NULL;
+ GFile *dir, *file;
+ gchar *path;
+ gint remaining = -1;
+
+ dir = g_file_enumerator_get_container (enumerator);
+ file = g_file_get_child (dir, g_file_info_get_name (file_info));
+ path = g_file_get_path (file);
+
+ /* FIXME: both file_is_valid_content() and create_content() are likely to block */
+ if (file_is_valid_content (path, FALSE)) {
+ if (operation->skipped < ss->skip)
+ operation->skipped++;
+ else
+ media = create_content (NULL, path, ss->flags & GRL_RESOLVE_FAST_ONLY, FALSE);
+ }
+
+ g_free (path);
+ g_object_unref (file);
+
+ if (media) {
+ operation->found_count++;
+ if (operation->found_count == ss->count)
+ remaining = 0;
+ ss->callback (ss->source, ss->search_id, media, remaining, ss->user_data, NULL);
+ if (!remaining)
+ /* after a call to the callback with remaining=0, the core will free
+ * the search spec */
+ operation->ss = NULL;
+ }
+ }
+
+ g_free (haystack);
+ g_free (normalized_haystack);
+ g_free (needle);
+ g_free (normalized_needle);
+ return operation->ss != NULL;
+}
+
+static void
+got_file (GFileEnumerator *enumerator, GAsyncResult *res, SearchOperation *operation)
+{
+ GList *files;
+ GError *error = NULL;
+
+ GRL_DEBUG ("got_file");
+
+ files = g_file_enumerator_next_files_finish (enumerator, res, &error);
+ if (error) {
+ GRL_WARNING ("Got error while searching: %s", error->message);
+ g_error_free (error);
+ goto finished;
+ }
+
+ if (files) {
+ GFileInfo *file_info;
+ /* we assume there is only one GFileInfo in the list since that's what we ask
+ * for when calling g_file_enumerator_next_files_async() */
+ file_info = (GFileInfo *)files->data;
+ g_list_free (files);
+ switch (g_file_info_get_file_type (file_info)) {
+ case G_FILE_TYPE_SYMBOLIC_LINK:
+ /* we're too afraid of infinite recursion to touch this for now */
+ break;
+ case G_FILE_TYPE_DIRECTORY:
+ {
+ GFile *dir, *subdir;
+
+ dir = g_file_enumerator_get_container (enumerator);
+ subdir = g_file_get_child (dir,
+ g_file_info_get_name (file_info));
+
+ g_queue_push_tail (operation->directories, subdir);
+ }
+ break;
+ case G_FILE_TYPE_REGULAR:
+ if (!compare_and_return_file (operation, enumerator, file_info)){
+ g_object_unref (file_info);
+ goto finished;
+ }
+ break;
+ default:
+ /* this file is a weirdo, we ignore it */
+ break;
+ }
+ g_object_unref (file_info);
+ } else { /* end of enumerator */
+ goto finished;
+ }
+
+ g_file_enumerator_next_files_async (enumerator, 1, G_PRIORITY_DEFAULT, NULL,
+ (GAsyncReadyCallback)got_file, operation);
+
+ return;
+
+finished:
+ /* we're done with this dir/enumerator, let's treat the next one */
+ g_object_unref (enumerator);
+ search_next_directory (operation);
+}
+
+static void
+got_children (GFile *directory, GAsyncResult *res, SearchOperation *operation)
+{
+ GError *error = NULL;
+ GFileEnumerator *enumerator;
+
+ GRL_DEBUG ("got_children");
+
+ enumerator = g_file_enumerate_children_finish (directory, res, &error);
+ if (error) {
+ GRL_WARNING ("Got error while searching: %s", error->message);
+ g_error_free (error);
+ g_object_unref (enumerator);
+ /* we couldn't get the children of this directory, but we probably have
+ * other directories to try */
+ search_next_directory (operation);
+ goto exit;
+ }
+
+ g_file_enumerator_next_files_async (enumerator, 1, G_PRIORITY_DEFAULT, NULL,
+ (GAsyncReadyCallback)got_file, operation);
+
+exit:
+ g_object_unref (directory);
+}
+
+static void
+search_next_directory (SearchOperation *operation)
+{
+ GFile *directory;
+ GrlMediaSourceSearchSpec *ss = operation->ss;
+
+ GRL_DEBUG ("search_next_directory");
+
+ if (!ss) { /* count reached, last callback call done */
+ goto finished;
+ }
+
+ directory = g_queue_pop_head (operation->directories);
+ if (!directory) { /* We've crawled everything, before reaching count */
+ ss->callback (ss->source, ss->search_id, NULL, 0, ss->user_data, NULL);
+ operation->ss = NULL;
+ goto finished;
+ }
+
+ g_file_enumerate_children_async (directory, G_FILE_ATTRIBUTE_STANDARD_TYPE ","
+ G_FILE_ATTRIBUTE_STANDARD_NAME ","
+ G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME,
+ G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
+ G_PRIORITY_DEFAULT,
+ NULL,
+ (GAsyncReadyCallback)got_children,
+ operation);
+
+ return;
+
+finished:
+ search_operation_free (operation);
+}
+
+
/* ================== API Implementation ================ */
static const GList *
@@ -613,6 +837,34 @@ grl_filesystem_source_browse (GrlMediaSource *source,
}
}
+static void grl_filesystem_source_search (GrlMediaSource *source,
+ GrlMediaSourceSearchSpec *ss)
+{
+ SearchOperation *operation;
+ GList *chosen_paths, *path;
+
+ GRL_DEBUG ("grl_filesystem_source_search");
+
+ operation = search_operation_new (source, ss);
+
+ chosen_paths = GRL_FILESYSTEM_SOURCE(source)->priv->chosen_paths;
+ if (chosen_paths) {
+ for (path = chosen_paths; path; path = g_list_next (path)) {
+ GFile *directory = g_file_new_for_path (path->data);
+ g_queue_push_tail (operation->directories, directory);
+ }
+ } else {
+ const gchar *home;
+ GFile *directory;
+
+ home = g_getenv ("HOME");
+ directory = g_file_new_for_path (home);
+ g_queue_push_tail (operation->directories, directory);
+ }
+
+ search_next_directory (operation);
+}
+
static void
grl_filesystem_source_metadata (GrlMediaSource *source,
GrlMediaSourceMetadataSpec *ms)
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]