diff options
author | Martyn Russell <martyn@lanedo.com> | 2010-12-07 12:15:42 +0000 |
---|---|---|
committer | Martyn Russell <martyn@lanedo.com> | 2010-12-09 23:53:51 +0000 |
commit | bb87eada6ba87a9eb398289ff8558898169f1a3d (patch) | |
tree | 28f2800107c0737ae83b4eb9b41a0e4de3379d48 /gtk/gtksearchenginetracker.c | |
parent | ddb5e12e6156480035c107954aa90cab94504a05 (diff) | |
download | gtk+-bb87eada6ba87a9eb398289ff8558898169f1a3d.tar.gz |
gtksearchenginetracker: Update to work with libtracker-sparql
libtracker-sparql is available in Tracker 0.9/0.10
Diffstat (limited to 'gtk/gtksearchenginetracker.c')
-rw-r--r-- | gtk/gtksearchenginetracker.c | 571 |
1 files changed, 284 insertions, 287 deletions
diff --git a/gtk/gtksearchenginetracker.c b/gtk/gtksearchenginetracker.c index e46691a944..ad9ff7fe2f 100644 --- a/gtk/gtksearchenginetracker.c +++ b/gtk/gtksearchenginetracker.c @@ -1,5 +1,4 @@ /* - * Copyright (C) 2005 Jamie McCracken <jamiemcc@gnome.org> * Copyright (C) 2009-2010 Nokia <ivan.frade@nokia.com> * * This library is free software; you can redistribute it and/or @@ -16,163 +15,143 @@ * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * - * Authors: Jamie McCracken <jamiemcc@gnome.org> - * Jürg Billeter <juerg.billeter@codethink.co.uk> + * Authors: Jürg Billeter <juerg.billeter@codethink.co.uk> * Martyn Russell <martyn@lanedo.com> * * Based on nautilus-search-engine-tracker.c */ #include "config.h" -#include <gmodule.h> -#include "gtksearchenginetracker.h" -/* we dlopen() libtracker at runtime */ +#include <gio/gio.h> +#include <gmodule.h> -typedef struct _TrackerClient TrackerClient; +#include "gtksearchenginetracker.h" -typedef enum -{ - TRACKER_UNAVAILABLE = 0, - TRACKER_0_6 = 1 << 0, - TRACKER_0_7 = 1 << 1, - TRACKER_0_8 = 1 << 2, - TRACKER_0_9 = 1 << 3 -} TrackerVersion; - - -/* Tracker 0.6 API */ -typedef void (*TrackerArrayReply) (char **result, - GError *error, - gpointer user_data); - -static TrackerClient * - (*tracker_connect) (gboolean enable_warnings, - gint timeout) = NULL; -static void (*tracker_disconnect) (TrackerClient *client) = NULL; -static int (*tracker_get_version) (TrackerClient *client, - GError **error) = NULL; -static void (*tracker_cancel_last_call) (TrackerClient *client) = NULL; - -static void (*tracker_search_metadata_by_text_async) (TrackerClient *client, - const char *query, - TrackerArrayReply callback, - gpointer user_data) = NULL; -static void (*tracker_search_metadata_by_text_and_location_async) (TrackerClient *client, - const char *query, - const char *location, - TrackerArrayReply callback, - gpointer user_data) = NULL; - - -/* Tracker 0.7->0.9 API */ -typedef enum { - TRACKER_CLIENT_ENABLE_WARNINGS = 1 << 0 -} TrackerClientFlags; - -typedef void (*TrackerReplyGPtrArray) (GPtrArray *result, - GError *error, - gpointer user_data); - -static TrackerClient * (*tracker_client_new) (TrackerClientFlags flags, - gint timeout) = NULL; -static gchar * (*tracker_sparql_escape) (const gchar *str) = NULL; -static guint (*tracker_resources_sparql_query_async) (TrackerClient *client, - const gchar *query, - TrackerReplyGPtrArray callback, - gpointer user_data) = NULL; - - -static struct TrackerDlMapping -{ - const char *fn_name; - gpointer *fn_ptr_ref; - TrackerVersion versions; -} tracker_dl_mapping[] = +/* If defined, we use fts:match, this has to be enabled in Tracker to + * work which it usually is. The alternative is to undefine it and + * use filename matching instead. This doesn't use the content of the + * file however. + */ +#undef FTS_MATCHING + +#define MODULE_FILENAME "libtracker-sparql-0.10.so.0" + +#define MODULE_MAP(a) { #a, (gpointer *)&a } + +/* Connection object */ +typedef struct _TrackerSparqlConnection TrackerSparqlConnection; + +#define TRACKER_SPARQL_TYPE_CONNECTION (tracker_sparql_connection_get_type ()) +#define TRACKER_SPARQL_CONNECTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TRACKER_SPARQL_TYPE_CONNECTION, TrackerSparqlConnection)) + +/* Cursor object */ +typedef struct _TrackerSparqlCursor TrackerSparqlCursor; + +#define TRACKER_SPARQL_TYPE_CURSOR (tracker_sparql_cursor_get_type ()) +#define TRACKER_SPARQL_CURSOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TRACKER_SPARQL_TYPE_CURSOR, TrackerSparqlCursor)) + +/* API */ +static GType (*tracker_sparql_connection_get_type) (void) = NULL; +static TrackerSparqlConnection * (*tracker_sparql_connection_get) (GCancellable *cancellable, + GError **error) = NULL; +static void (*tracker_sparql_connection_query_async) (TrackerSparqlConnection *self, + const gchar *sparql, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) = NULL; +static TrackerSparqlCursor * (*tracker_sparql_connection_query_finish) (TrackerSparqlConnection *self, + GAsyncResult *_res_, + GError **error) = NULL; +static GType (*tracker_sparql_cursor_get_type) (void) = NULL; +static void (*tracker_sparql_cursor_next_async) (TrackerSparqlCursor *self, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) = NULL; +static gboolean (*tracker_sparql_cursor_next_finish) (TrackerSparqlCursor *self, + GAsyncResult *_res_, + GError **error) = NULL; +static const gchar * (*tracker_sparql_cursor_get_string) (TrackerSparqlCursor *self, + gint *column, + glong *length) = NULL; +static gchar * (*tracker_sparql_escape_string) (const gchar *literal) = NULL; + +static struct TrackerFunctions { -#define MAP(a,v) { #a, (gpointer *)&a, v } - MAP (tracker_connect, TRACKER_0_6 | TRACKER_0_7), - MAP (tracker_disconnect, TRACKER_0_6 | TRACKER_0_7), - MAP (tracker_get_version, TRACKER_0_6), - MAP (tracker_cancel_last_call, TRACKER_0_6 | TRACKER_0_7 | TRACKER_0_8 | TRACKER_0_9), - MAP (tracker_search_metadata_by_text_async, TRACKER_0_6 | TRACKER_0_7), - MAP (tracker_search_metadata_by_text_and_location_async, TRACKER_0_6 | TRACKER_0_7), - MAP (tracker_client_new, TRACKER_0_8 | TRACKER_0_9), - MAP (tracker_sparql_escape, TRACKER_0_8 | TRACKER_0_9), - MAP (tracker_resources_sparql_query_async, TRACKER_0_8 | TRACKER_0_9) -#undef MAP + const char *name; + gpointer *pointer; +} funcs[] = { + MODULE_MAP (tracker_sparql_connection_get_type), + MODULE_MAP (tracker_sparql_connection_get), + MODULE_MAP (tracker_sparql_connection_query_async), + MODULE_MAP (tracker_sparql_connection_query_finish), + MODULE_MAP (tracker_sparql_cursor_get_type), + MODULE_MAP (tracker_sparql_cursor_next_async), + MODULE_MAP (tracker_sparql_cursor_next_finish), + MODULE_MAP (tracker_sparql_cursor_get_string), + MODULE_MAP (tracker_sparql_escape_string) }; -static TrackerVersion -open_libtracker (void) +static gboolean +init (void) { - static gboolean done = FALSE; - static TrackerVersion version = TRACKER_UNAVAILABLE; - - if (!done) - { - gint i; - GModule *tracker; - GModuleFlags flags; - - done = TRUE; - flags = G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL; - - /* So this is the order: - * - * - 0.9 (latest unstable) - * - 0.8 (stable) - * - 0.7 (unstable, 0.6 sucks so badly) - * - 0.6 (stable) - */ - if ((tracker = g_module_open ("libtracker-client-0.9.so.0", flags)) != NULL) - version = TRACKER_0_9; - else if ((tracker = g_module_open ("libtracker-client-0.8.so.0", flags)) != NULL) - version = TRACKER_0_8; - else if ((tracker = g_module_open ("libtracker-client-0.7.so.0", flags)) != NULL) - version = TRACKER_0_7; - else if ((tracker = g_module_open ("libtrackerclient.so.0", flags)) != NULL) - version = TRACKER_0_6; - else - { - g_debug ("No tracker backend available"); - return TRACKER_UNAVAILABLE; - } - - for (i = 0; i < G_N_ELEMENTS (tracker_dl_mapping); i++) - { - if ((tracker_dl_mapping[i].versions & version) == 0) - continue; - - if (!g_module_symbol (tracker, - tracker_dl_mapping[i].fn_name, - tracker_dl_mapping[i].fn_ptr_ref)) - { - g_warning ("Missing symbol '%s' in libtracker\n", - tracker_dl_mapping[i].fn_name); - g_module_close (tracker); - - for (i = 0; i < G_N_ELEMENTS (tracker_dl_mapping); i++) - tracker_dl_mapping[i].fn_ptr_ref = NULL; - - return TRACKER_UNAVAILABLE; + static gboolean inited = FALSE; + gint i; + GModule *m; + GModuleFlags flags; + + if (inited) + return TRUE; + + flags = G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL; + + /* Only support 0.10 onwards */ + if ((m = g_module_open (MODULE_FILENAME, flags)) == NULL) + { + g_debug ("No tracker backend available or it is not new enough"); + g_debug ("Only available using '%s'", MODULE_FILENAME); + return FALSE; + } + + inited = TRUE; + + /* Check for the symbols we need */ + for (i = 0; i < G_N_ELEMENTS (funcs); i++) + { + if (!g_module_symbol (m, funcs[i].name, funcs[i].pointer)) + { + g_warning ("Missing symbol '%s' in libtracker-sparql\n", + funcs[i].name); + g_module_close (m); + + for (i = 0; i < G_N_ELEMENTS (funcs); i++) + funcs[i].pointer = NULL; + + return FALSE; + } } - } - } - return version; + g_debug ("Loaded Tracker library and all required symbols"); + + return TRUE; } +/* + * GtkSearchEngineTracker object + */ struct _GtkSearchEngineTrackerPrivate { - GtkQuery *query; - TrackerClient *client; - gboolean query_pending; - TrackerVersion version; + TrackerSparqlConnection *connection; + GCancellable *cancellable; + GtkQuery *query; + gboolean query_pending; }; G_DEFINE_TYPE (GtkSearchEngineTracker, _gtk_search_engine_tracker, GTK_TYPE_SEARCH_ENGINE); +static void cursor_callback (GObject *object, + GAsyncResult *result, + gpointer user_data); static void finalize (GObject *object) @@ -181,56 +160,106 @@ finalize (GObject *object) tracker = GTK_SEARCH_ENGINE_TRACKER (object); + if (tracker->priv->cancellable) + { + g_cancellable_cancel (tracker->priv->cancellable); + g_object_unref (tracker->priv->cancellable); + tracker->priv->cancellable = NULL; + } + if (tracker->priv->query) { g_object_unref (tracker->priv->query); tracker->priv->query = NULL; } - if (tracker->priv->version == TRACKER_0_8 || - tracker->priv->version == TRACKER_0_9) - g_object_unref (tracker->priv->client); - else - tracker_disconnect (tracker->priv->client); + if (tracker->priv->connection) + { + g_object_unref (tracker->priv->connection); + tracker->priv->connection = NULL; + } G_OBJECT_CLASS (_gtk_search_engine_tracker_parent_class)->finalize (object); } +static void +cursor_next (GtkSearchEngineTracker *tracker, + TrackerSparqlCursor *cursor) +{ + tracker_sparql_cursor_next_async (cursor, + tracker->priv->cancellable, + cursor_callback, + tracker); +} -/* stolen from tracker sources, tracker.c */ static void -sparql_append_string_literal (GString *sparql, - const gchar *str) +cursor_callback (GObject *object, + GAsyncResult *result, + gpointer user_data) { - gchar *s; + GtkSearchEngineTracker *tracker; + GError *error = NULL; + TrackerSparqlCursor *cursor; + GList *hits; + gboolean success; - s = tracker_sparql_escape (str); + tracker = GTK_SEARCH_ENGINE_TRACKER (user_data); - g_string_append_c (sparql, '"'); - g_string_append (sparql, s); - g_string_append_c (sparql, '"'); + cursor = TRACKER_SPARQL_CURSOR (object); + success = tracker_sparql_cursor_next_finish (cursor, result, &error); - g_free (s); -} + if (error) + { + _gtk_search_engine_error (GTK_SEARCH_ENGINE (tracker), error->message); + + g_error_free (error); + + if (cursor) + g_object_unref (cursor); + + return; + } + + if (!success) + { + _gtk_search_engine_finished (GTK_SEARCH_ENGINE (tracker)); + + if (cursor) + g_object_unref (cursor); + + return; + } + + /* We iterate result by result, not n at a time. */ + hits = g_list_append (NULL, (gchar*) tracker_sparql_cursor_get_string (cursor, 0, NULL)); + _gtk_search_engine_hits_added (GTK_SEARCH_ENGINE (tracker), hits); + g_list_free (hits); + /* Get next */ + cursor_next (tracker, cursor); +} static void -search_callback (gpointer results, - GError *error, - gpointer user_data) +query_callback (GObject *object, + GAsyncResult *result, + gpointer user_data) { GtkSearchEngineTracker *tracker; - gchar **results_p; - GList *hit_uris; - GPtrArray *OUT_result; - gchar *uri; - gint i; + TrackerSparqlConnection *connection; + TrackerSparqlCursor *cursor; + GError *error = NULL; tracker = GTK_SEARCH_ENGINE_TRACKER (user_data); - hit_uris = NULL; tracker->priv->query_pending = FALSE; + connection = TRACKER_SPARQL_CONNECTION (object); + cursor = tracker_sparql_connection_query_finish (connection, + result, + &error); + + g_debug ("Query returned cursor:%p", cursor); + if (error) { _gtk_search_engine_error (GTK_SEARCH_ENGINE (tracker), error->message); @@ -238,118 +267,96 @@ search_callback (gpointer results, return; } - if (!results) - return; + if (!cursor) + { + _gtk_search_engine_finished (GTK_SEARCH_ENGINE (tracker)); + return; + } - if (tracker->priv->version == TRACKER_0_8 || - tracker->priv->version == TRACKER_0_9) - { - OUT_result = (GPtrArray*) results; + cursor_next (tracker, cursor); +} - for (i = 0; i < OUT_result->len; i++) - { - uri = g_strdup (((gchar **) OUT_result->pdata[i])[0]); - if (uri) - hit_uris = g_list_prepend (hit_uris, uri); - } +static void +sparql_append_string_literal (GString *sparql, + const gchar *str) +{ + gchar *s; - g_ptr_array_foreach (OUT_result, (GFunc) g_free, NULL); - g_ptr_array_free (OUT_result, TRUE); - } - else - { - for (results_p = results; *results_p; results_p++) - { - if (tracker->priv->version == TRACKER_0_6) - uri = g_filename_to_uri (*results_p, NULL, NULL); - else - uri = g_strdup (*results_p); - - if (uri) - hit_uris = g_list_prepend (hit_uris, uri); - } - g_strfreev ((gchar **) results); - } + s = tracker_sparql_escape_string (str); - _gtk_search_engine_hits_added (GTK_SEARCH_ENGINE (tracker), hit_uris); - _gtk_search_engine_finished (GTK_SEARCH_ENGINE (tracker)); + g_string_append_c (sparql, '"'); + g_string_append (sparql, s); + g_string_append_c (sparql, '"'); - g_list_foreach (hit_uris, (GFunc) g_free, NULL); - g_list_free (hit_uris); + g_free (s); } - static void gtk_search_engine_tracker_start (GtkSearchEngine *engine) { GtkSearchEngineTracker *tracker; - gchar *search_text, *location, *location_uri; + gchar *search_text, *location_uri; GString *sparql; tracker = GTK_SEARCH_ENGINE_TRACKER (engine); if (tracker->priv->query_pending) - return; + { + g_debug ("Attempt to start a new search while one is pending, doing nothing"); + return; + } if (tracker->priv->query == NULL) - return; + { + g_debug ("Attempt to start a new search with no GtkQuery, doing nothing"); + return; + } search_text = _gtk_query_get_text (tracker->priv->query); location_uri = _gtk_query_get_location (tracker->priv->query); - location = NULL; - if (location_uri) - { - if (tracker->priv->version == TRACKER_0_6) - { - location = g_filename_from_uri (location_uri, NULL, NULL); - g_free (location_uri); - } - else - location = location_uri; - } + g_debug ("Query starting, search criteria:'%s', location:'%s'", search_text, location_uri); - if (tracker->priv->version == TRACKER_0_8 || - tracker->priv->version == TRACKER_0_9) - { - sparql = g_string_new ("SELECT nie:url(?urn) WHERE { ?urn a nfo:FileDataObject; fts:match "); - sparql_append_string_literal (sparql, search_text); - if (location) - { - g_string_append (sparql, " . FILTER (fn:starts-with(nie:url(?urn),"); - sparql_append_string_literal (sparql, location); - g_string_append (sparql, "))"); - } - g_string_append (sparql, " } ORDER BY DESC(fts:rank(?urn)) ASC(nie:url(?urn))"); - - tracker_resources_sparql_query_async (tracker->priv->client, - sparql->str, - (TrackerReplyGPtrArray) search_callback, - tracker); - g_string_free (sparql, TRUE); - } - else - { - if (location) - { - tracker_search_metadata_by_text_and_location_async (tracker->priv->client, - search_text, - location, - (TrackerArrayReply) search_callback, - tracker); - } - else - { - tracker_search_metadata_by_text_async (tracker->priv->client, - search_text, - (TrackerArrayReply) search_callback, - tracker); - } - } + /* Using FTS: */ + sparql = g_string_new ("SELECT nie:url(?urn) " + "WHERE {" + " ?urn a nfo:FileDataObject ;" + " tracker:available true ; " + " fts:match "); + sparql_append_string_literal (sparql, search_text); + +#ifdef FTS_MATCHING + if (location_uri) + { + g_string_append (sparql, " . FILTER (fn:starts-with(nie:url(?urn),"); + sparql_append_string_literal (sparql, location_uri); + g_string_append (sparql, "))"); + } + + g_string_append (sparql, " } ORDER BY DESC(fts:rank(?urn)) ASC(nie:url(?urn))"); +#else /* FTS_MATCHING */ + /* Using filename matching: */ + sparql = g_string_new ("SELECT nie:url(?urn) " + "WHERE {" + " ?urn a nfo:FileDataObject ;" + " tracker:available true ." + " FILTER (fn:contains(nfo:fileName(?urn),"); + sparql_append_string_literal (sparql, search_text); + + g_string_append (sparql, + "))" + "} ORDER BY DESC(nie:url(?urn)) DESC(nfo:fileName(?urn))"); +#endif /* FTS_MATCHING */ + + tracker_sparql_connection_query_async (tracker->priv->connection, + sparql->str, + tracker->priv->cancellable, + query_callback, + tracker); + g_string_free (sparql, TRUE); tracker->priv->query_pending = TRUE; g_free (search_text); - g_free (location); } static void @@ -359,9 +366,11 @@ gtk_search_engine_tracker_stop (GtkSearchEngine *engine) tracker = GTK_SEARCH_ENGINE_TRACKER (engine); + g_debug ("Query stopping"); + if (tracker->priv->query && tracker->priv->query_pending) { - tracker_cancel_last_call (tracker->priv->client); + g_cancellable_cancel (tracker->priv->cancellable); tracker->priv->query_pending = FALSE; } } @@ -374,7 +383,7 @@ gtk_search_engine_tracker_is_indexed (GtkSearchEngine *engine) static void gtk_search_engine_tracker_set_query (GtkSearchEngine *engine, - GtkQuery *query) + GtkQuery *query) { GtkSearchEngineTracker *tracker; @@ -410,7 +419,9 @@ _gtk_search_engine_tracker_class_init (GtkSearchEngineTrackerClass *class) static void _gtk_search_engine_tracker_init (GtkSearchEngineTracker *engine) { - engine->priv = G_TYPE_INSTANCE_GET_PRIVATE (engine, GTK_TYPE_SEARCH_ENGINE_TRACKER, GtkSearchEngineTrackerPrivate); + engine->priv = G_TYPE_INSTANCE_GET_PRIVATE (engine, + GTK_TYPE_SEARCH_ENGINE_TRACKER, + GtkSearchEngineTrackerPrivate); } @@ -418,49 +429,35 @@ GtkSearchEngine * _gtk_search_engine_tracker_new (void) { GtkSearchEngineTracker *engine; - TrackerClient *tracker_client; - TrackerVersion version; - GError *err = NULL; - - version = open_libtracker (); - - if (version == TRACKER_0_8 || - version == TRACKER_0_9) - { - tracker_client = tracker_client_new (TRACKER_CLIENT_ENABLE_WARNINGS, G_MAXINT); - } - else - { - if (!tracker_connect) - return NULL; - - tracker_client = tracker_connect (FALSE, -1); - } - - if (!tracker_client) - return NULL; - - - if (version == TRACKER_0_6) - { - if (!tracker_get_version) - return NULL; - - tracker_get_version (tracker_client, &err); - - if (err != NULL) - { - g_error_free (err); - tracker_disconnect (tracker_client); - return NULL; - } - } + TrackerSparqlConnection *connection; + GCancellable *cancellable; + GError *error = NULL; + + if (!init ()) + return NULL; + + g_debug ("Creating GtkSearchEngineTracker..."); + + cancellable = g_cancellable_new (); + connection = tracker_sparql_connection_get (cancellable, &error); + + if (error) + { + g_warning ("Could not establish a connection to Tracker: %s", error->message); + g_error_free (error); + return NULL; + } + else if (!connection) + { + g_warning ("Could not establish a connection to Tracker, no TrackerSparqlConnection was returned"); + return NULL; + } engine = g_object_new (GTK_TYPE_SEARCH_ENGINE_TRACKER, NULL); - engine->priv->client = tracker_client; + engine->priv->connection = connection; + engine->priv->cancellable = cancellable; engine->priv->query_pending = FALSE; - engine->priv->version = version; return GTK_SEARCH_ENGINE (engine); } |