diff options
author | Emmanuele Bassi <ebassi@gnome.org> | 2007-05-02 22:51:43 +0000 |
---|---|---|
committer | Emmanuele Bassi <ebassi@src.gnome.org> | 2007-05-02 22:51:43 +0000 |
commit | d3aeccf774fd13c4efdbdb873bb2258e1b94f853 (patch) | |
tree | 4ce2f324a2518663451f7e82cb0d9da97b7ee5b2 /gtk/gtksearchenginesimple.c | |
parent | e82e337ee915d0cb1f07640be53a76854684b181 (diff) | |
download | gtk+-d3aeccf774fd13c4efdbdb873bb2258e1b94f853.tar.gz |
Add search file support in the GtkFileChooser. Original patch by Federico
2007-05-02 Emmanuele Bassi <ebassi@gnome.org>
Add search file support in the GtkFileChooser. Original patch
by Federico Mena Quintero; patch updated by Matthias Clasen.
See bug #344785.
* gtk/gtksearchengine.[ch]: Private search engine abstraction
object.
* gtk/gtksearchenginebeagle.[ch]: Private search engine
implementation using libbeagle (via g_module_open()).
* gtk/gtksearchenginesimple.[ch]: Private search engine
implementation using file tree walking.
* gtk/gtksearchenginetracker.[ch]: Private earch engine
implementation using libtracker (via g_module_open()).
* gtk/gtkquery.[ch]: Private query object for the search
engines.
* gtk/gtkfilechooserprivate.h:
* gtk/gtkfilechooserdefault.c: Use the GtkSearchEngine to
query a search engine backend using GtkQuery; create a new
operating mode, OPERATION_MODE_SEARCH, and call the common
operating mode OPERATION_MODE_BROWSE; add support for virtual
shortcuts inside the shortcuts model and create a new "Search"
virtual shortcut.
* gtk/Makefile.am: Update the build with the new files
svn path=/trunk/; revision=17783
Diffstat (limited to 'gtk/gtksearchenginesimple.c')
-rw-r--r-- | gtk/gtksearchenginesimple.c | 378 |
1 files changed, 378 insertions, 0 deletions
diff --git a/gtk/gtksearchenginesimple.c b/gtk/gtksearchenginesimple.c new file mode 100644 index 0000000000..bfe1aec138 --- /dev/null +++ b/gtk/gtksearchenginesimple.c @@ -0,0 +1,378 @@ +/* + * Copyright (C) 2005 Red Hat, Inc + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * + * Author: Alexander Larsson <alexl@redhat.com> + * + * Based on nautilus-search-engine-simple.c + */ + +#define _XOPEN_SOURCE 500 +#define _GNU_SOURCE + +#include <config.h> +#include "gtksearchenginesimple.h" + +#define XDG_PREFIX _gtk_xdg +#include "xdgmime/xdgmime.h" + +#include <string.h> +#include <ftw.h> +#include <glib/gstrfuncs.h> + +#define BATCH_SIZE 500 + +typedef struct +{ + GtkSearchEngineSimple *engine; + + gchar *path; + GList *mime_types; + gchar **words; + GList *found_list; + + gint n_processed_files; + GList *uri_hits; + + /* accessed on both threads: */ + volatile gboolean cancelled; +} SearchThreadData; + + +struct _GtkSearchEngineSimplePrivate +{ + GtkQuery *query; + + SearchThreadData *active_search; + + gboolean query_finished; +}; + + +G_DEFINE_TYPE (GtkSearchEngineSimple, _gtk_search_engine_simple, GTK_TYPE_SEARCH_ENGINE); + +static void +finalize (GObject *object) +{ + GtkSearchEngineSimple *simple; + + simple = GTK_SEARCH_ENGINE_SIMPLE (object); + + if (simple->priv->query) + { + g_object_unref (simple->priv->query); + simple->priv->query = NULL; + } + + g_free (simple->priv); + + G_OBJECT_CLASS (_gtk_search_engine_simple_parent_class)->finalize (object); +} + +static SearchThreadData * +search_thread_data_new (GtkSearchEngineSimple *engine, + GtkQuery *query) +{ + SearchThreadData *data; + char *text, *lower, *uri; + + data = g_new0 (SearchThreadData, 1); + + data->engine = engine; + uri = _gtk_query_get_location (query); + if (uri != NULL) + { + data->path = g_filename_from_uri (uri, NULL, NULL); + g_free (uri); + } + if (data->path == NULL) + data->path = g_strdup (g_get_home_dir ()); + + text = _gtk_query_get_text (query); + lower = g_ascii_strdown (text, -1); + data->words = g_strsplit (lower, " ", -1); + g_free (text); + g_free (lower); + + data->mime_types = _gtk_query_get_mime_types (query); + + return data; +} + +static void +search_thread_data_free (SearchThreadData *data) +{ + g_free (data->path); + g_strfreev (data->words); + g_list_foreach (data->mime_types, (GFunc)g_free, NULL); + g_list_free (data->mime_types); + g_free (data); +} + +static gboolean +search_thread_done_idle (gpointer user_data) +{ + SearchThreadData *data; + + data = user_data; + + if (!data->cancelled) + { + _gtk_search_engine_finished (GTK_SEARCH_ENGINE (data->engine)); + data->engine->priv->active_search = NULL; + } + + search_thread_data_free (data); + + return FALSE; +} + +typedef struct +{ + GList *uris; + SearchThreadData *thread_data; +} SearchHits; + + +static gboolean +search_thread_add_hits_idle (gpointer user_data) +{ + SearchHits *hits; + + hits = user_data; + + if (!hits->thread_data->cancelled) + { + _gtk_search_engine_hits_added (GTK_SEARCH_ENGINE (hits->thread_data->engine), + hits->uris); + } + + g_list_foreach (hits->uris, (GFunc)g_free, NULL); + g_list_free (hits->uris); + g_free (hits); + + return FALSE; +} + +static void +send_batch (SearchThreadData *data) +{ + SearchHits *hits; + + data->n_processed_files = 0; + + if (data->uri_hits) + { + hits = g_new (SearchHits, 1); + hits->uris = data->uri_hits; + hits->thread_data = data; + g_idle_add (search_thread_add_hits_idle, hits); + } + data->uri_hits = NULL; +} + +static GStaticPrivate search_thread_data = G_STATIC_PRIVATE_INIT; + +static int +search_visit_func (const char *fpath, + const struct stat *sb, + int typeflag, + struct FTW *ftwbuf) +{ + SearchThreadData *data; + gint i; + const gchar *name; + gchar *lower_name, *path, *mime_type; + gchar *uri; + gboolean hit; + GList *l; + gboolean is_hidden; + + data = (SearchThreadData*)g_static_private_get (&search_thread_data); + + if (data->cancelled) + return FTW_STOP; + + name = strrchr (fpath, '/'); + if (name) + name++; + else + name = fpath; + + path = g_build_filename (data->path, fpath, NULL); + + is_hidden = *name == '.'; + + hit = FALSE; + + if (!is_hidden) + { + lower_name = g_ascii_strdown (name, -1); + + hit = TRUE; + for (i = 0; data->words[i] != NULL; i++) + { + if (strstr (lower_name, data->words[i]) == NULL) + { + hit = FALSE; + break; + } + } + g_free (lower_name); + } + + if (hit && data->mime_types != NULL) + { + hit = FALSE; + mime_type = xdg_mime_get_mime_type_for_file (path, (struct stat *)sb); + for (l = data->mime_types; l != NULL; l = l->next) + { + if (strcmp (mime_type, l->data) == 0) + { + hit = TRUE; + break; + } + } + + g_free (mime_type); + } + + if (hit) + { + uri = g_filename_to_uri (path, NULL, NULL); + data->uri_hits = g_list_prepend (data->uri_hits, uri); + } + + data->n_processed_files++; + + if (data->n_processed_files > BATCH_SIZE) + send_batch (data); + + if (is_hidden) + return FTW_SKIP_SUBTREE; + else + return FTW_CONTINUE; +} + +static gpointer +search_thread_func (gpointer user_data) +{ + SearchThreadData *data; + + data = user_data; + + g_static_private_set (&search_thread_data, data, NULL); + + nftw (data->path, search_visit_func, 20, FTW_ACTIONRETVAL | FTW_PHYS); + + send_batch (data); + + g_idle_add (search_thread_done_idle, data); + + return NULL; +} + +static void +gtk_search_engine_simple_start (GtkSearchEngine *engine) +{ + GtkSearchEngineSimple *simple; + SearchThreadData *data; + + simple = GTK_SEARCH_ENGINE_SIMPLE (engine); + + if (simple->priv->active_search != NULL) + return; + + if (simple->priv->query == NULL) + return; + + data = search_thread_data_new (simple, simple->priv->query); + + g_thread_create (search_thread_func, data, FALSE, NULL); + + simple->priv->active_search = data; +} + +static void +gtk_search_engine_simple_stop (GtkSearchEngine *engine) +{ + GtkSearchEngineSimple *simple; + + simple = GTK_SEARCH_ENGINE_SIMPLE (engine); + + if (simple->priv->active_search != NULL) + { + simple->priv->active_search->cancelled = TRUE; + simple->priv->active_search = NULL; + } +} + +static gboolean +gtk_search_engine_simple_is_indexed (GtkSearchEngine *engine) +{ + return FALSE; +} + +static void +gtk_search_engine_simple_set_query (GtkSearchEngine *engine, + GtkQuery *query) +{ + GtkSearchEngineSimple *simple; + + simple = GTK_SEARCH_ENGINE_SIMPLE (engine); + + if (query) + g_object_ref (query); + + if (simple->priv->query) + g_object_unref (simple->priv->query); + + simple->priv->query = query; +} + +static void +_gtk_search_engine_simple_class_init (GtkSearchEngineSimpleClass *class) +{ + GObjectClass *gobject_class; + GtkSearchEngineClass *engine_class; + + gobject_class = G_OBJECT_CLASS (class); + gobject_class->finalize = finalize; + + engine_class = GTK_SEARCH_ENGINE_CLASS (class); + engine_class->set_query = gtk_search_engine_simple_set_query; + engine_class->start = gtk_search_engine_simple_start; + engine_class->stop = gtk_search_engine_simple_stop; + engine_class->is_indexed = gtk_search_engine_simple_is_indexed; + + g_type_class_add_private (gobject_class, sizeof (GtkSearchEngineSimplePrivate)); +} + +static void +_gtk_search_engine_simple_init (GtkSearchEngineSimple *engine) +{ + engine->priv = G_TYPE_INSTANCE_GET_PRIVATE (engine, GTK_TYPE_SEARCH_ENGINE_SIMPLE, GtkSearchEngineSimplePrivate); +} + +GtkSearchEngine * +_gtk_search_engine_simple_new (void) +{ + GtkSearchEngine *engine; + + engine = g_object_new (GTK_TYPE_SEARCH_ENGINE_SIMPLE, NULL); + + return engine; +} |