Fixed #374055:Only the first "tag" is detected in digikam.
[beagle.git] / libbeagle / beagle / beagle-query.c
blob484128dcdc367587bb97d644c6e34efebf221976
1 /*
2 * beagle-query.c
4 * Copyright (C) 2005 Novell, Inc.
6 */
8 /*
9 * Permission is hereby granted, free of charge, to any person obtaining a
10 * copy of this software and associated documentation files (the "Software"),
11 * to deal in the Software without restriction, including without limitation
12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 * and/or sell copies of the Software, and to permit persons to whom the
14 * Software is furnished to do so, subject to the following conditions:
16 * The above copyright notice and this permission notice shall be included in
17 * all copies or substantial portions of the Software.
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25 * DEALINGS IN THE SOFTWARE.
28 #include <stdlib.h>
29 #include <sys/types.h>
30 #include <sys/socket.h>
31 #include <sys/un.h>
33 #include "beagle-finished-response.h"
34 #include "beagle-hits-added-response.h"
35 #include "beagle-hits-subtracted-response.h"
36 #include "beagle-marshal.h"
37 #include "beagle-query.h"
38 #include "beagle-query-part.h"
39 #include "beagle-query-part-human.h"
40 #include "beagle-query-part-or.h"
41 #include "beagle-query-part-property.h"
42 #include "beagle-search-term-response.h"
43 #include "beagle-private.h"
45 typedef struct {
46 GSList *parts; /* of BeagleQueryPart */
47 GSList *mime_types; /* of string */
48 GSList *hit_types; /* of string */
49 GSList *sources; /* of string */
50 int max_hits;
52 /* These are extracted from the BeagleSearchTermResponse */
53 GSList *exact_text; /* of string */
54 GSList *stemmed_text; /* of string */
56 BeagleQueryDomain domain;
57 } BeagleQueryPrivate;
59 #define BEAGLE_QUERY_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), BEAGLE_TYPE_QUERY, BeagleQueryPrivate))
61 enum {
62 HITS_ADDED,
63 HITS_SUBTRACTED,
64 FINISHED,
65 LAST_SIGNAL
68 static GObjectClass *parent_class = NULL;
69 static guint signals [LAST_SIGNAL] = { 0 };
71 static void
72 query_set_search_terms (BeagleQuery *query, BeagleSearchTermResponse *response)
74 BeagleQueryPrivate *priv = BEAGLE_QUERY_GET_PRIVATE (query);
76 priv->exact_text = _beagle_search_term_response_get_exact_text (response);
77 priv->stemmed_text = _beagle_search_term_response_get_stemmed_text (response);
80 static GString *
81 beagle_query_to_xml (BeagleRequest *request, GError **err)
83 BeagleQueryPrivate *priv = BEAGLE_QUERY_GET_PRIVATE (request);
84 GString *data = g_string_new (NULL);
85 GString *sub_data;
86 BeagleQueryPartOr *or_part;
87 GSList *iter;
88 gboolean first = TRUE;
90 _beagle_request_append_standard_header (data, "Query");
92 g_string_append_len (data, "<Parts>", 7);
94 if (priv->mime_types != NULL) {
95 or_part = beagle_query_part_or_new ();
97 for (iter = priv->mime_types; iter!= NULL; iter = iter->next) {
98 BeagleQueryPartProperty *prop_part = beagle_query_part_property_new ();
100 beagle_query_part_property_set_property_type (prop_part, BEAGLE_PROPERTY_TYPE_KEYWORD);
101 beagle_query_part_property_set_key (prop_part, "beagle:MimeType");
102 beagle_query_part_property_set_value (prop_part, (const char *) iter->data);
104 beagle_query_part_or_add_subpart (or_part, BEAGLE_QUERY_PART (prop_part));
107 sub_data = _beagle_query_part_to_xml (BEAGLE_QUERY_PART (or_part));
108 g_string_append_len (data, sub_data->str, sub_data->len);
109 g_string_free (sub_data, TRUE);
110 g_object_unref (or_part);
113 if (priv->hit_types != NULL) {
114 or_part = beagle_query_part_or_new ();
116 for (iter = priv->hit_types; iter!= NULL; iter = iter->next) {
117 BeagleQueryPartProperty *prop_part = beagle_query_part_property_new ();
119 beagle_query_part_property_set_property_type (prop_part, BEAGLE_PROPERTY_TYPE_KEYWORD);
120 beagle_query_part_property_set_key (prop_part, "beagle:HitType");
121 beagle_query_part_property_set_value (prop_part, (const char *) iter->data);
123 beagle_query_part_or_add_subpart (or_part, BEAGLE_QUERY_PART (prop_part));
126 sub_data = _beagle_query_part_to_xml (BEAGLE_QUERY_PART (or_part));
127 g_string_append_len (data, sub_data->str, sub_data->len);
128 g_string_free (sub_data, TRUE);
129 g_object_unref (or_part);
132 if (priv->sources != NULL) {
133 or_part = beagle_query_part_or_new ();
135 for (iter = priv->sources; iter!= NULL; iter = iter->next) {
136 BeagleQueryPartProperty *prop_part = beagle_query_part_property_new ();
138 beagle_query_part_property_set_property_type (prop_part, BEAGLE_PROPERTY_TYPE_KEYWORD);
139 beagle_query_part_property_set_key (prop_part, "beagle:Source");
140 beagle_query_part_property_set_value (prop_part, (const char *) iter->data);
142 beagle_query_part_or_add_subpart (or_part, BEAGLE_QUERY_PART (prop_part));
145 sub_data = _beagle_query_part_to_xml (BEAGLE_QUERY_PART (or_part));
146 g_string_append_len (data, sub_data->str, sub_data->len);
147 g_string_free (sub_data, TRUE);
148 g_object_unref (or_part);
151 for (iter = priv->parts; iter != NULL; iter = iter->next) {
152 BeagleQueryPart *part = (BeagleQueryPart *) iter->data;
154 sub_data = _beagle_query_part_to_xml (part);
155 g_string_append_len (data, sub_data->str, sub_data->len);
156 g_string_free (sub_data, TRUE);
159 g_string_append_len (data, "</Parts>", 8);
161 g_string_append_len (data, "<MimeTypes>", 11);
163 for (iter = priv->mime_types; iter != NULL; iter = iter->next) {
164 const char *mime_type = (const char *) iter->data;
166 g_string_append_printf (data, "<MimeType>%s</MimeType>", mime_type);
169 g_string_append_len (data, "</MimeTypes>", 12);
171 g_string_append_len (data, "<HitTypes>", 10);
173 for (iter = priv->hit_types; iter != NULL; iter = iter->next) {
174 const char *hit_type = (const char *) iter->data;
176 g_string_append_printf (data, "<HitType>%s</HitType>", hit_type);
179 g_string_append_len (data, "</HitTypes>", 11);
181 g_string_append_len (data, "<Sources>", 9);
183 for (iter = priv->sources; iter != NULL; iter = iter->next) {
184 const char *source = (const char *) iter->data;
186 g_string_append_printf (data, "<Source>%s</Source>", source);
189 g_string_append_len (data, "</Sources>", 10);
191 g_string_append_len (data, "<QueryDomain>", 13);
193 if (priv->domain & BEAGLE_QUERY_DOMAIN_LOCAL) {
194 g_string_append_len (data, "Local", 5);
195 first = FALSE;
198 if (priv->domain & BEAGLE_QUERY_DOMAIN_SYSTEM) {
199 if (!first)
200 g_string_append_c (data, ' ');
202 g_string_append_len (data, "System", 6);
203 first = FALSE;
206 if (priv->domain & BEAGLE_QUERY_DOMAIN_NEIGHBORHOOD) {
207 if (!first)
208 g_string_append_c (data, ' ');
210 g_string_append_len (data, "Neighborhood", 12);
211 first = FALSE;
214 if (priv->domain & BEAGLE_QUERY_DOMAIN_GLOBAL) {
215 if (!first)
216 g_string_append_c (data, ' ');
218 g_string_append_len (data, "Global", 6);
221 g_string_append_len (data, "</QueryDomain>", 14);
223 g_string_append_printf (data, "<MaxHits>%d</MaxHits>", priv->max_hits);
225 _beagle_request_append_standard_footer (data);
227 return data;
230 static void
231 beagle_query_response (BeagleRequest *request, BeagleResponse *response)
233 if (BEAGLE_IS_SEARCH_TERM_RESPONSE (response)) {
234 query_set_search_terms (BEAGLE_QUERY (request),
235 BEAGLE_SEARCH_TERM_RESPONSE (response));
236 } else if (BEAGLE_IS_HITS_ADDED_RESPONSE (response))
237 g_signal_emit (request, signals[HITS_ADDED], 0, response);
238 else if (BEAGLE_IS_HITS_SUBTRACTED_RESPONSE (response))
239 g_signal_emit (request, signals[HITS_SUBTRACTED], 0, response);
240 else if (BEAGLE_IS_FINISHED_RESPONSE (response))
241 g_signal_emit (request, signals[FINISHED], 0, response);
246 G_DEFINE_TYPE (BeagleQuery, beagle_query, BEAGLE_TYPE_REQUEST)
248 static void
249 beagle_query_finalize (GObject *obj)
251 BeagleQueryPrivate *priv = BEAGLE_QUERY_GET_PRIVATE (obj);
253 g_slist_foreach (priv->parts, (GFunc) g_object_unref, NULL);
254 g_slist_free (priv->parts);
256 g_slist_foreach (priv->mime_types, (GFunc) g_free, NULL);
257 g_slist_free (priv->mime_types);
259 g_slist_foreach (priv->hit_types, (GFunc) g_free, NULL);
260 g_slist_free (priv->hit_types);
262 g_slist_foreach (priv->sources, (GFunc) g_free, NULL);
263 g_slist_free (priv->sources);
265 g_slist_foreach (priv->exact_text, (GFunc) g_free, NULL);
266 g_slist_free (priv->exact_text);
268 g_slist_foreach (priv->stemmed_text, (GFunc) g_free, NULL);
269 g_slist_free (priv->stemmed_text);
272 if (G_OBJECT_CLASS (parent_class)->finalize)
273 G_OBJECT_CLASS (parent_class)->finalize (obj);
276 static void
277 beagle_query_class_init (BeagleQueryClass *klass)
279 GObjectClass *obj_class = G_OBJECT_CLASS (klass);
280 BeagleRequestClass *request_class = BEAGLE_REQUEST_CLASS (klass);
282 parent_class = g_type_class_peek_parent (klass);
284 obj_class->finalize = beagle_query_finalize;
285 request_class->to_xml = beagle_query_to_xml;
287 request_class->response = beagle_query_response;
289 signals [HITS_ADDED] =
290 g_signal_new ("hits_added",
291 G_TYPE_FROM_CLASS (klass),
292 G_SIGNAL_RUN_LAST,
293 G_STRUCT_OFFSET (BeagleQueryClass, hits_added),
294 NULL, NULL,
295 g_cclosure_marshal_VOID__OBJECT,
296 G_TYPE_NONE, 1,
297 BEAGLE_TYPE_HITS_ADDED_RESPONSE);
299 signals [HITS_SUBTRACTED] =
300 g_signal_new ("hits_subtracted",
301 G_TYPE_FROM_CLASS (klass),
302 G_SIGNAL_RUN_LAST,
303 G_STRUCT_OFFSET (BeagleQueryClass, hits_subtracted),
304 NULL, NULL,
305 g_cclosure_marshal_VOID__OBJECT,
306 G_TYPE_NONE, 1,
307 BEAGLE_TYPE_HITS_SUBTRACTED_RESPONSE);
309 signals [FINISHED] =
310 g_signal_new ("finished",
311 G_TYPE_FROM_CLASS (klass),
312 G_SIGNAL_RUN_LAST,
313 G_STRUCT_OFFSET (BeagleQueryClass, finished),
314 NULL, NULL,
315 g_cclosure_marshal_VOID__OBJECT,
316 G_TYPE_NONE, 1,
317 BEAGLE_TYPE_FINISHED_RESPONSE);
319 g_type_class_add_private (klass, sizeof (BeagleQueryPrivate));
321 _beagle_request_class_set_response_types (request_class,
322 "HitsAddedResponse",
323 BEAGLE_TYPE_HITS_ADDED_RESPONSE,
324 "HitsSubtractedResponse",
325 BEAGLE_TYPE_HITS_SUBTRACTED_RESPONSE,
326 "FinishedResponse",
327 BEAGLE_TYPE_FINISHED_RESPONSE,
328 "SearchTermResponse",
329 BEAGLE_TYPE_SEARCH_TERM_RESPONSE,
330 NULL);
333 static void
334 beagle_query_init (BeagleQuery *query)
336 BeagleQueryPrivate *priv = BEAGLE_QUERY_GET_PRIVATE (query);
338 priv->max_hits = 100;
340 /* FIXME: This is a good default when on an airplane. */
341 priv->domain = BEAGLE_QUERY_DOMAIN_LOCAL | BEAGLE_QUERY_DOMAIN_SYSTEM;
345 * beagle_query_new:
347 * Creates a new #BeagleQuery.
349 * Return value: the newly created #BeagleQuery.
351 BeagleQuery *
352 beagle_query_new (void)
354 BeagleQuery *query = g_object_new (BEAGLE_TYPE_QUERY, 0);
356 return query;
360 * beagle_query_add_part:
361 * @query: a #BeagleQuery
362 * @part: a #BeagleQueryPart
364 * Adds a #BeagleQueryPart to the given #BeagleQuery.
366 void
367 beagle_query_add_part (BeagleQuery *query, BeagleQueryPart *part)
369 BeagleQueryPrivate *priv = BEAGLE_QUERY_GET_PRIVATE (query);
371 g_return_if_fail (BEAGLE_IS_QUERY (query));
373 priv->parts = g_slist_append (priv->parts, part);
377 * beagle_query_add_text:
378 * @query: a #BeagleQuery
379 * @str: a string
381 * Adds a text part to the given #BeagleQuery.
383 void
384 beagle_query_add_text (BeagleQuery *query, const char *str)
386 BeagleQueryPartHuman *part;
388 g_return_if_fail (BEAGLE_IS_QUERY (query));
390 part = beagle_query_part_human_new ();
391 beagle_query_part_human_set_string (part, str);
392 beagle_query_part_set_logic (BEAGLE_QUERY_PART (part),
393 BEAGLE_QUERY_PART_LOGIC_REQUIRED);
395 beagle_query_add_part (query, BEAGLE_QUERY_PART (part));
400 * beagle_query_add_mime_type:
401 * @query: a #BeagleQuery
402 * @mime_type: a mime type
404 * Adds an allowed mime type to the given #BeagleQuery.
406 void
407 beagle_query_add_mime_type (BeagleQuery *query,
408 const char *mime_type)
410 BeagleQueryPrivate *priv;
412 g_return_if_fail (BEAGLE_IS_QUERY (query));
413 g_return_if_fail (mime_type != NULL);
415 priv = BEAGLE_QUERY_GET_PRIVATE (query);
417 priv->mime_types = g_slist_prepend (priv->mime_types, g_strdup (mime_type));
421 * beagle_query_add_hit_type:
422 * @query: a #BeagleQuery
423 * @hit_type: a hit type
425 * Adds an allowed hit type to the given #BeagleQuery.
427 void
428 beagle_query_add_hit_type (BeagleQuery *query,
429 const char *hit_type)
431 BeagleQueryPrivate *priv;
433 g_return_if_fail (BEAGLE_IS_QUERY (query));
434 g_return_if_fail (hit_type != NULL);
436 priv = BEAGLE_QUERY_GET_PRIVATE (query);
438 priv->hit_types = g_slist_prepend (priv->hit_types, g_strdup (hit_type));
442 * beagle_query_add_source:
443 * @query: a #BeagleQuery
444 * @source: a source
446 * Adds an allowed source to the given #BeagleQuery.
448 void
449 beagle_query_add_source (BeagleQuery *query,
450 const char *source)
452 BeagleQueryPrivate *priv;
454 g_return_if_fail (BEAGLE_IS_QUERY (query));
455 g_return_if_fail (source != NULL);
457 priv = BEAGLE_QUERY_GET_PRIVATE (query);
459 priv->sources = g_slist_prepend (priv->sources, g_strdup (source));
463 * beagle_query_set_domain:
464 * @query: a #BeagleQuery
465 * @domain: a #BeagleQueryDomain
467 * Sets the search domain for a given #BeagleQuery. This limits the scope of
468 * a search to certain backends.
470 void
471 beagle_query_set_domain (BeagleQuery *query,
472 BeagleQueryDomain domain)
474 BeagleQueryPrivate *priv;
476 g_return_if_fail (BEAGLE_IS_QUERY (query));
478 priv = BEAGLE_QUERY_GET_PRIVATE (query);
480 priv->domain = domain;
484 * beagle_query_add_domain:
485 * @query: a #BeagleQuery
486 * @domain: a #BeagleQueryDomain
488 * Adds a search domain to the list of domains to search.
490 void
491 beagle_query_add_domain (BeagleQuery *query,
492 BeagleQueryDomain domain)
494 BeagleQueryPrivate *priv;
496 g_return_if_fail (BEAGLE_IS_QUERY (query));
498 priv = BEAGLE_QUERY_GET_PRIVATE (query);
500 priv->domain |= domain;
504 * beagle_query_remove_domain:
505 * @query: a #BeagleQuery
506 * @domain: a #BeagleQueryDomain
508 * Removes a search domain.
510 void
511 beagle_query_remove_domain (BeagleQuery *query,
512 BeagleQueryDomain domain)
514 BeagleQueryPrivate *priv;
516 g_return_if_fail (BEAGLE_IS_QUERY (query));
518 priv = BEAGLE_QUERY_GET_PRIVATE (query);
520 priv->domain &= ~domain;
524 * beagle_query_set_max_hits
525 * @query: a #BeagleQuery
526 * @max_hits: Max number of hits
528 * Sets the max number of hits a given #BeagleQuery should return.
530 void
531 beagle_query_set_max_hits (BeagleQuery *query,
532 int max_hits)
534 BeagleQueryPrivate *priv;
536 g_return_if_fail (BEAGLE_IS_QUERY (query));
538 priv = BEAGLE_QUERY_GET_PRIVATE (query);
540 priv->max_hits = max_hits;
545 * beagle_query_get_max_hits
546 * @query: a #BeagleQuery
548 * Returns the max number of hits a given #BeagleQuery should return.
550 * Return value: Max number of hits
553 beagle_query_get_max_hits (BeagleQuery *query)
555 BeagleQueryPrivate *priv;
557 g_return_val_if_fail (BEAGLE_IS_QUERY (query), 0);
559 priv = BEAGLE_QUERY_GET_PRIVATE (query);
561 return priv->max_hits;
565 * beagle_query_get_exact_text
566 * @query: a #BeagleQuery
568 * Returns a list of strings which contain the exact text processed by the
569 * query. The list should not be modified or freed.
571 * Return value: A list of strings containing the exact text
573 GSList *
574 beagle_query_get_exact_text (BeagleQuery *query)
576 BeagleQueryPrivate *priv;
578 g_return_val_if_fail (BEAGLE_IS_QUERY (query), 0);
580 priv = BEAGLE_QUERY_GET_PRIVATE (query);
582 return priv->exact_text;
586 * beagle_query_get_stemmed_text
587 * @query: a #BeagleQuery
589 * Returns a list of strings which contain the stemmed text processed by the
590 * query. The list should not be modified or freed.
592 * Return value: A list of strings containing the stemmed text
594 GSList *
595 beagle_query_get_stemmed_text (BeagleQuery *query)
597 BeagleQueryPrivate *priv;
599 g_return_val_if_fail (BEAGLE_IS_QUERY (query), 0);
601 priv = BEAGLE_QUERY_GET_PRIVATE (query);
603 return priv->stemmed_text;