summaryrefslogtreecommitdiff
path: root/gtk/gtksearchenginesimple.c
diff options
context:
space:
mode:
authorEmmanuele Bassi <ebassi@gnome.org>2007-05-02 22:51:43 +0000
committerEmmanuele Bassi <ebassi@src.gnome.org>2007-05-02 22:51:43 +0000
commitd3aeccf774fd13c4efdbdb873bb2258e1b94f853 (patch)
tree4ce2f324a2518663451f7e82cb0d9da97b7ee5b2 /gtk/gtksearchenginesimple.c
parente82e337ee915d0cb1f07640be53a76854684b181 (diff)
downloadgtk+-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.c378
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;
+}