Skip to content

Commit e919e2d

Browse files
J08nYleio
andauthored
Add tracker support (#2334)
* Revert "Remove tracker" This reverts commit 5db7a44. * meson: Try tracker-2 Co-authored-by: Mart Raudsepp <leio@gentoo.org>
1 parent e5b6798 commit e919e2d

6 files changed

Lines changed: 471 additions & 1 deletion

File tree

libnemo-private/meson.build

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,11 @@ if libexif_enabled
9191
nemo_private_deps += libexif
9292
endif
9393

94+
if tracker_enabled
95+
nemo_private_sources += 'nemo-search-engine-tracker.c'
96+
nemo_private_deps += tracker_sparql
97+
endif
98+
9499
if libselinux_enabled
95100
nemo_private_deps += libselinux
96101
endif
Lines changed: 379 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,379 @@
1+
/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2+
/*
3+
* Copyright (C) 2005 Mr Jamie McCracken
4+
*
5+
* Nemo is free software; you can redistribute it and/or
6+
* modify it under the terms of the GNU General Public License as
7+
* published by the Free Software Foundation; either version 2 of the
8+
* License, or (at your option) any later version.
9+
*
10+
* Nemo is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13+
* General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU General Public
16+
* License along with this program; see the file COPYING. If not,
17+
* write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500,
18+
* Boston, MA 02110-1335, USA.
19+
*
20+
* Author: Jamie McCracken <jamiemcc@gnome.org>
21+
*
22+
*/
23+
24+
#include <config.h>
25+
#include "nemo-search-engine-tracker.h"
26+
#include <gmodule.h>
27+
#include <string.h>
28+
#include <gio/gio.h>
29+
30+
#include <libtracker-sparql/tracker-sparql.h>
31+
32+
/* If defined, we use fts:match, this has to be enabled in Tracker to
33+
* work which it usually is. The alternative is to undefine it and
34+
* use filename matching instead. This doesn't use the content of the
35+
* file however.
36+
*/
37+
#undef FTS_MATCHING
38+
39+
struct NemoSearchEngineTrackerDetails {
40+
TrackerSparqlConnection *connection;
41+
NemoQuery *query;
42+
43+
gboolean query_pending;
44+
GCancellable *cancellable;
45+
};
46+
47+
G_DEFINE_TYPE (NemoSearchEngineTracker,
48+
nemo_search_engine_tracker,
49+
NEMO_TYPE_SEARCH_ENGINE);
50+
51+
static void
52+
finalize (GObject *object)
53+
{
54+
NemoSearchEngineTracker *tracker;
55+
56+
tracker = NEMO_SEARCH_ENGINE_TRACKER (object);
57+
58+
g_clear_object (&tracker->details->query);
59+
g_clear_object (&tracker->details->cancellable);
60+
g_clear_object (&tracker->details->connection);
61+
62+
G_OBJECT_CLASS (nemo_search_engine_tracker_parent_class)->finalize (object);
63+
}
64+
65+
66+
/* stolen from tracker sources, tracker.c */
67+
static void
68+
sparql_append_string_literal (GString *sparql,
69+
const gchar *str)
70+
{
71+
char *s;
72+
73+
s = tracker_sparql_escape_string (str);
74+
75+
g_string_append_c (sparql, '"');
76+
g_string_append (sparql, s);
77+
g_string_append_c (sparql, '"');
78+
79+
g_free (s);
80+
}
81+
82+
static void cursor_callback (GObject *object,
83+
GAsyncResult *result,
84+
gpointer user_data);
85+
86+
static void
87+
cursor_next (NemoSearchEngineTracker *tracker,
88+
TrackerSparqlCursor *cursor)
89+
{
90+
tracker_sparql_cursor_next_async (cursor,
91+
tracker->details->cancellable,
92+
cursor_callback,
93+
tracker);
94+
}
95+
96+
static void
97+
cursor_callback (GObject *object,
98+
GAsyncResult *result,
99+
gpointer user_data)
100+
{
101+
NemoSearchEngineTracker *tracker;
102+
GError *error = NULL;
103+
TrackerSparqlCursor *cursor;
104+
GList *hits;
105+
gboolean success;
106+
107+
tracker = NEMO_SEARCH_ENGINE_TRACKER (user_data);
108+
109+
cursor = TRACKER_SPARQL_CURSOR (object);
110+
success = tracker_sparql_cursor_next_finish (cursor, result, &error);
111+
112+
if (error) {
113+
tracker->details->query_pending = FALSE;
114+
nemo_search_engine_error (NEMO_SEARCH_ENGINE (tracker), error->message);
115+
g_error_free (error);
116+
g_object_unref (cursor);
117+
118+
return;
119+
}
120+
121+
if (!success) {
122+
tracker->details->query_pending = FALSE;
123+
nemo_search_engine_finished (NEMO_SEARCH_ENGINE (tracker));
124+
g_object_unref (cursor);
125+
126+
return;
127+
}
128+
129+
/* We iterate result by result, not n at a time. */
130+
hits = g_list_append (NULL, (gchar*) tracker_sparql_cursor_get_string (cursor, 0, NULL));
131+
nemo_search_engine_hits_added (NEMO_SEARCH_ENGINE (tracker), hits);
132+
g_list_free (hits);
133+
134+
/* Get next */
135+
cursor_next (tracker, cursor);
136+
}
137+
138+
static void
139+
query_callback (GObject *object,
140+
GAsyncResult *result,
141+
gpointer user_data)
142+
{
143+
NemoSearchEngineTracker *tracker;
144+
TrackerSparqlConnection *connection;
145+
TrackerSparqlCursor *cursor;
146+
GError *error = NULL;
147+
148+
tracker = NEMO_SEARCH_ENGINE_TRACKER (user_data);
149+
150+
connection = TRACKER_SPARQL_CONNECTION (object);
151+
cursor = tracker_sparql_connection_query_finish (connection,
152+
result,
153+
&error);
154+
155+
if (error) {
156+
tracker->details->query_pending = FALSE;
157+
nemo_search_engine_error (NEMO_SEARCH_ENGINE (tracker), error->message);
158+
g_error_free (error);
159+
return;
160+
}
161+
162+
if (!cursor) {
163+
tracker->details->query_pending = FALSE;
164+
nemo_search_engine_finished (NEMO_SEARCH_ENGINE (tracker));
165+
return;
166+
}
167+
168+
cursor_next (tracker, cursor);
169+
}
170+
171+
static void
172+
nemo_search_engine_tracker_start (NemoSearchEngine *engine)
173+
{
174+
NemoSearchEngineTracker *tracker;
175+
gchar *search_text, *location_uri;
176+
GString *sparql;
177+
GList *mimetypes, *l;
178+
gint mime_count;
179+
180+
tracker = NEMO_SEARCH_ENGINE_TRACKER (engine);
181+
182+
if (tracker->details->query_pending) {
183+
return;
184+
}
185+
186+
if (tracker->details->query == NULL) {
187+
return;
188+
}
189+
190+
g_cancellable_reset (tracker->details->cancellable);
191+
192+
search_text = nemo_query_get_text (tracker->details->query);
193+
location_uri = nemo_query_get_location (tracker->details->query);
194+
mimetypes = nemo_query_get_mime_types (tracker->details->query);
195+
196+
mime_count = g_list_length (mimetypes);
197+
198+
#ifdef FTS_MATCHING
199+
/* Using FTS: */
200+
sparql = g_string_new ("SELECT nie:url(?urn) "
201+
"WHERE {"
202+
" ?urn a nfo:FileDataObject ;"
203+
" tracker:available true ; ");
204+
205+
if (mime_count > 0) {
206+
g_string_append (sparql, "nie:mimeType ?mime ;");
207+
}
208+
209+
g_string_append (sparql, " fts:match ");
210+
sparql_append_string_literal (sparql, search_text);
211+
212+
if (location_uri || mime_count > 0) {
213+
g_string_append (sparql, " . FILTER (");
214+
215+
if (location_uri) {
216+
g_string_append (sparql, " fn:starts-with(nie:url(?urn),");
217+
sparql_append_string_literal (sparql, location_uri);
218+
g_string_append (sparql, ")");
219+
}
220+
221+
if (mime_count > 0) {
222+
if (location_uri) {
223+
g_string_append (sparql, " && ");
224+
}
225+
226+
g_string_append (sparql, "(");
227+
for (l = mimetypes; l != NULL; l = l->next) {
228+
if (l != mimetypes) {
229+
g_string_append (sparql, " || ");
230+
}
231+
232+
g_string_append (sparql, "?mime = ");
233+
sparql_append_string_literal (sparql, l->data);
234+
}
235+
g_string_append (sparql, ")");
236+
}
237+
238+
g_string_append (sparql, ")");
239+
}
240+
241+
g_string_append (sparql, " } ORDER BY DESC(fts:rank(?urn)) ASC(nie:url(?urn))");
242+
#else /* FTS_MATCHING */
243+
/* Using filename matching: */
244+
sparql = g_string_new ("SELECT nie:url(?urn) "
245+
"WHERE {"
246+
" ?urn a nfo:FileDataObject ;");
247+
248+
if (mime_count > 0) {
249+
g_string_append (sparql, "nie:mimeType ?mime ;");
250+
}
251+
252+
g_string_append (sparql, " tracker:available true ."
253+
" FILTER (fn:contains(nfo:fileName(?urn),");
254+
255+
sparql_append_string_literal (sparql, search_text);
256+
257+
g_string_append (sparql, ")");
258+
259+
if (location_uri) {
260+
g_string_append (sparql, " && fn:starts-with(nie:url(?urn),");
261+
sparql_append_string_literal (sparql, location_uri);
262+
g_string_append (sparql, ")");
263+
}
264+
265+
if (mime_count > 0) {
266+
g_string_append (sparql, " && ");
267+
g_string_append (sparql, "(");
268+
for (l = mimetypes; l != NULL; l = l->next) {
269+
if (l != mimetypes) {
270+
g_string_append (sparql, " || ");
271+
}
272+
273+
g_string_append (sparql, "?mime = ");
274+
sparql_append_string_literal (sparql, l->data);
275+
}
276+
g_string_append (sparql, ")");
277+
}
278+
279+
g_string_append (sparql, ")");
280+
281+
282+
g_string_append (sparql,
283+
"} ORDER BY DESC(nie:url(?urn)) DESC(nfo:fileName(?urn))");
284+
#endif /* FTS_MATCHING */
285+
286+
tracker_sparql_connection_query_async (tracker->details->connection,
287+
sparql->str,
288+
tracker->details->cancellable,
289+
query_callback,
290+
tracker);
291+
g_string_free (sparql, TRUE);
292+
293+
tracker->details->query_pending = TRUE;
294+
295+
g_free (search_text);
296+
g_free (location_uri);
297+
298+
if (mimetypes != NULL) {
299+
g_list_free_full (mimetypes, g_free);
300+
}
301+
}
302+
303+
static void
304+
nemo_search_engine_tracker_stop (NemoSearchEngine *engine)
305+
{
306+
NemoSearchEngineTracker *tracker;
307+
308+
tracker = NEMO_SEARCH_ENGINE_TRACKER (engine);
309+
310+
if (tracker->details->query && tracker->details->query_pending) {
311+
g_cancellable_cancel (tracker->details->cancellable);
312+
tracker->details->query_pending = FALSE;
313+
}
314+
}
315+
316+
static void
317+
nemo_search_engine_tracker_set_query (NemoSearchEngine *engine, NemoQuery *query)
318+
{
319+
NemoSearchEngineTracker *tracker;
320+
321+
tracker = NEMO_SEARCH_ENGINE_TRACKER (engine);
322+
323+
if (query) {
324+
g_object_ref (query);
325+
}
326+
327+
if (tracker->details->query) {
328+
g_object_unref (tracker->details->query);
329+
}
330+
331+
tracker->details->query = query;
332+
}
333+
334+
static void
335+
nemo_search_engine_tracker_class_init (NemoSearchEngineTrackerClass *class)
336+
{
337+
GObjectClass *gobject_class;
338+
NemoSearchEngineClass *engine_class;
339+
340+
gobject_class = G_OBJECT_CLASS (class);
341+
gobject_class->finalize = finalize;
342+
343+
engine_class = NEMO_SEARCH_ENGINE_CLASS (class);
344+
engine_class->set_query = nemo_search_engine_tracker_set_query;
345+
engine_class->start = nemo_search_engine_tracker_start;
346+
engine_class->stop = nemo_search_engine_tracker_stop;
347+
348+
g_type_class_add_private (class, sizeof (NemoSearchEngineTrackerDetails));
349+
}
350+
351+
static void
352+
nemo_search_engine_tracker_init (NemoSearchEngineTracker *engine)
353+
{
354+
engine->details = G_TYPE_INSTANCE_GET_PRIVATE (engine, NEMO_TYPE_SEARCH_ENGINE_TRACKER,
355+
NemoSearchEngineTrackerDetails);
356+
}
357+
358+
359+
NemoSearchEngine *
360+
nemo_search_engine_tracker_new (void)
361+
{
362+
NemoSearchEngineTracker *engine;
363+
TrackerSparqlConnection *connection;
364+
GError *error = NULL;
365+
366+
connection = tracker_sparql_connection_get (NULL, &error);
367+
368+
if (error) {
369+
g_warning ("Could not establish a connection to Tracker: %s", error->message);
370+
g_error_free (error);
371+
return NULL;
372+
}
373+
374+
engine = g_object_new (NEMO_TYPE_SEARCH_ENGINE_TRACKER, NULL);
375+
engine->details->connection = connection;
376+
engine->details->cancellable = g_cancellable_new ();
377+
378+
return NEMO_SEARCH_ENGINE (engine);
379+
}

0 commit comments

Comments
 (0)