summaryrefslogtreecommitdiff
path: root/gtk/gtksearchenginetracker3.c
diff options
context:
space:
mode:
authorCarlos Garnacho <carlosg@gnome.org>2020-05-17 00:04:56 +0200
committerCarlos Garnacho <carlosg@gnome.org>2020-05-19 22:05:07 +0200
commit98f376a19e6287793c47d290dcf69e52429f5256 (patch)
tree7f8349ed1053ec7fe04a17d79172d59da271ae3e /gtk/gtksearchenginetracker3.c
parentde68925f0c58f910efd4d79a783881950597cc8f (diff)
downloadgtk+-98f376a19e6287793c47d290dcf69e52429f5256.tar.gz
gtksearchengine: Add tracker3 search engine
Make this dependency optional at build time, and prefer it over the old tracker <= 2.x implementation.
Diffstat (limited to 'gtk/gtksearchenginetracker3.c')
-rw-r--r--gtk/gtksearchenginetracker3.c338
1 files changed, 338 insertions, 0 deletions
diff --git a/gtk/gtksearchenginetracker3.c b/gtk/gtksearchenginetracker3.c
new file mode 100644
index 0000000000..1debfc24ca
--- /dev/null
+++ b/gtk/gtksearchenginetracker3.c
@@ -0,0 +1,338 @@
+/*
+ * Copyright (C) 2020 Red Hat Inc
+ * Copyright (C) 2009-2011 Nokia <ivan.frade@nokia.com>
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Carlos Garnacho <carlosg@gnome.org>
+ * Jürg Billeter <juerg.billeter@codethink.co.uk>
+ * Martyn Russell <martyn@lanedo.com>
+ *
+ * Based on nautilus-search-engine-tracker.c
+ */
+
+#include "config.h"
+
+#include <string.h>
+
+#include <gio/gio.h>
+#include <gmodule.h>
+#include <gdk/gdk.h>
+#include <gtk/gtk.h>
+#include <libtracker-sparql/tracker-sparql.h>
+
+#include "gtksearchenginetracker3.h"
+
+#define MINER_FS_BUS_NAME "org.freedesktop.Tracker3.Miner.Files"
+
+#define SEARCH_QUERY_BASE(__PATTERN__) \
+ "SELECT ?url " \
+ "FROM tracker:FileSystem " \
+ "WHERE {" \
+ " ?urn a nfo:FileDataObject ;" \
+ " nie:url ?url ; " \
+ " fts:match ~match . " \
+ __PATTERN__ \
+ "} " \
+ "ORDER BY DESC(fts:rank(?urn)) DESC(?url)"
+
+#define SEARCH_QUERY SEARCH_QUERY_BASE("")
+#define SEARCH_RECURSIVE_QUERY SEARCH_QUERY_BASE("?urn (nfo:belongsToContainer/nie:isStoredAs)+/nie:url ~location")
+#define SEARCH_LOCATION_QUERY SEARCH_QUERY_BASE("?urn nfo:belongsToContainer/nie:isStoredAs/nie:url ~location")
+
+struct _GtkSearchEngineTracker3
+{
+ GtkSearchEngine parent;
+ TrackerSparqlConnection *sparql_conn;
+ TrackerSparqlStatement *search_query;
+ TrackerSparqlStatement *search_recursive_query;
+ TrackerSparqlStatement *search_location_query;
+ GCancellable *cancellable;
+ GtkQuery *query;
+ gboolean query_pending;
+};
+
+struct _GtkSearchEngineTracker3Class
+{
+ GtkSearchEngineClass parent_class;
+};
+
+static void gtk_search_engine_tracker3_initable_iface_init (GInitableIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (GtkSearchEngineTracker3,
+ gtk_search_engine_tracker3,
+ GTK_TYPE_SEARCH_ENGINE,
+ G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
+ gtk_search_engine_tracker3_initable_iface_init))
+
+static void
+finalize (GObject *object)
+{
+ GtkSearchEngineTracker3 *engine;
+
+ g_debug ("Finalizing GtkSearchEngineTracker3");
+
+ engine = GTK_SEARCH_ENGINE_TRACKER3 (object);
+
+ if (engine->cancellable)
+ {
+ g_cancellable_cancel (engine->cancellable);
+ g_object_unref (engine->cancellable);
+ }
+
+ g_clear_object (&engine->search_query);
+ g_clear_object (&engine->search_location_query);
+ tracker_sparql_connection_close (engine->sparql_conn);
+ g_clear_object (&engine->sparql_conn);
+
+ G_OBJECT_CLASS (gtk_search_engine_tracker3_parent_class)->finalize (object);
+}
+
+static void
+free_hit (gpointer data)
+{
+ GtkSearchHit *hit = data;
+
+ g_clear_object (&hit->file);
+ g_clear_object (&hit->info);
+ g_slice_free (GtkSearchHit, hit);
+}
+
+static void
+query_callback (TrackerSparqlStatement *statement,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ GtkSearchEngineTracker3 *engine;
+ TrackerSparqlCursor *cursor;
+ GList *hits = NULL;
+ GError *error = NULL;
+ GtkSearchHit *hit;
+
+ engine = GTK_SEARCH_ENGINE_TRACKER3 (user_data);
+
+ engine->query_pending = FALSE;
+
+ cursor = tracker_sparql_statement_execute_finish (statement, res, &error);
+
+ if (!cursor)
+ {
+ _gtk_search_engine_error (GTK_SEARCH_ENGINE (engine), error->message);
+ g_error_free (error);
+ g_object_unref (engine);
+ return;
+ }
+
+ while (tracker_sparql_cursor_next (cursor, NULL, NULL))
+ {
+ const gchar *url;
+
+ url = tracker_sparql_cursor_get_string (cursor, 0, NULL);
+ hit = g_slice_new0 (GtkSearchHit);
+ hit->file = g_file_new_for_uri (url);
+ hits = g_list_prepend (hits, hit);
+ }
+
+ tracker_sparql_cursor_close (cursor);
+
+ _gtk_search_engine_hits_added (GTK_SEARCH_ENGINE (engine), hits);
+ _gtk_search_engine_finished (GTK_SEARCH_ENGINE (engine), hits != NULL);
+
+ g_list_free_full (hits, free_hit);
+ g_object_unref (engine);
+ g_object_unref (cursor);
+}
+
+static void
+gtk_search_engine_tracker3_start (GtkSearchEngine *engine)
+{
+ GtkSearchEngineTracker3 *tracker;
+ TrackerSparqlStatement *statement;
+ const gchar *search_text;
+ gboolean recursive;
+ gchar *match;
+ GFile *location;
+
+ tracker = GTK_SEARCH_ENGINE_TRACKER3 (engine);
+
+ if (tracker->query_pending)
+ {
+ g_debug ("Attempt to start a new search while one is pending, doing nothing");
+ return;
+ }
+
+ if (tracker->query == NULL)
+ {
+ g_debug ("Attempt to start a new search with no GtkQuery, doing nothing");
+ return;
+ }
+
+ tracker->query_pending = TRUE;
+ search_text = gtk_query_get_text (tracker->query);
+ location = gtk_query_get_location (tracker->query);
+ recursive = _gtk_search_engine_get_recursive (engine);
+
+ if (location)
+ {
+ gchar *location_uri = g_file_get_uri (location);
+
+ if (recursive)
+ {
+ g_debug ("Recursive search query in location: %s", location_uri);
+ statement = tracker->search_recursive_query;
+ }
+ else
+ {
+ g_debug ("Search query in location: %s", location_uri);
+ statement = tracker->search_location_query;
+ }
+
+ tracker_sparql_statement_bind_string (statement,
+ "location",
+ location_uri);
+ g_free (location_uri);
+ }
+ else
+ {
+ g_debug ("Search query");
+ statement = tracker->search_query;
+ }
+
+ match = g_strdup_printf ("%s*", search_text);
+ tracker_sparql_statement_bind_string (statement, "match", match);
+ g_debug ("search text: %s\n", match);
+ tracker_sparql_statement_execute_async (statement, tracker->cancellable,
+ (GAsyncReadyCallback) query_callback,
+ g_object_ref (tracker));
+ g_free (match);
+}
+
+static void
+gtk_search_engine_tracker3_stop (GtkSearchEngine *engine)
+{
+ GtkSearchEngineTracker3 *tracker;
+
+ tracker = GTK_SEARCH_ENGINE_TRACKER3 (engine);
+
+ if (tracker->query && tracker->query_pending)
+ {
+ g_cancellable_cancel (tracker->cancellable);
+ tracker->query_pending = FALSE;
+ }
+}
+
+static void
+gtk_search_engine_tracker3_set_query (GtkSearchEngine *engine,
+ GtkQuery *query)
+{
+ GtkSearchEngineTracker3 *tracker;
+
+ tracker = GTK_SEARCH_ENGINE_TRACKER3 (engine);
+
+ if (query)
+ g_object_ref (query);
+
+ if (tracker->query)
+ g_object_unref (tracker->query);
+
+ tracker->query = query;
+}
+
+static void
+gtk_search_engine_tracker3_class_init (GtkSearchEngineTracker3Class *class)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (class);
+ GtkSearchEngineClass *engine_class = GTK_SEARCH_ENGINE_CLASS (class);
+
+ gobject_class->finalize = finalize;
+
+ engine_class->set_query = gtk_search_engine_tracker3_set_query;
+ engine_class->start = gtk_search_engine_tracker3_start;
+ engine_class->stop = gtk_search_engine_tracker3_stop;
+}
+
+static void
+gtk_search_engine_tracker3_init (GtkSearchEngineTracker3 *engine)
+{
+ engine->cancellable = g_cancellable_new ();
+ engine->query_pending = FALSE;
+}
+
+static gboolean
+gtk_search_engine_tracker3_initable_init (GInitable *initable,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GtkSearchEngineTracker3 *engine;
+
+ engine = GTK_SEARCH_ENGINE_TRACKER3 (initable);
+
+ engine->sparql_conn = tracker_sparql_connection_bus_new (MINER_FS_BUS_NAME,
+ NULL, NULL,
+ error);
+ if (!engine->sparql_conn)
+ return FALSE;
+
+ engine->search_query =
+ tracker_sparql_connection_query_statement (engine->sparql_conn,
+ SEARCH_QUERY,
+ cancellable,
+ error);
+ if (!engine->search_query)
+ return FALSE;
+
+ engine->search_recursive_query =
+ tracker_sparql_connection_query_statement (engine->sparql_conn,
+ SEARCH_RECURSIVE_QUERY,
+ cancellable,
+ error);
+ if (!engine->search_recursive_query)
+ return FALSE;
+
+ engine->search_location_query =
+ tracker_sparql_connection_query_statement (engine->sparql_conn,
+ SEARCH_LOCATION_QUERY,
+ cancellable,
+ error);
+ if (!engine->search_location_query)
+ return FALSE;
+
+ return TRUE;
+}
+
+static void
+gtk_search_engine_tracker3_initable_iface_init (GInitableIface *iface)
+{
+ iface->init = gtk_search_engine_tracker3_initable_init;
+}
+
+GtkSearchEngine *
+gtk_search_engine_tracker3_new (void)
+{
+ GtkSearchEngineTracker3 *engine;
+ GError *error = NULL;
+
+ g_debug ("Creating GtkSearchEngineTracker3...");
+
+ engine = g_initable_new (GTK_TYPE_SEARCH_ENGINE_TRACKER3,
+ NULL, &error, NULL);
+ if (!engine)
+ {
+ g_critical ("Could not init tracker3 search engine: %s",
+ error->message);
+ g_error_free (error);
+ }
+
+ return GTK_SEARCH_ENGINE (engine);
+}