1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2 /*
3 * Copyright (C) 2005 Novell, Inc.
4 *
5 * Caja 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 * Caja 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 St, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19 *
20 * Author: Anders Carlsson <andersca@imendio.com>
21 *
22 */
23
24 #include <config.h>
25 #include <string.h>
26 #include <glib/gi18n.h>
27
28 #include <eel/eel-gtk-macros.h>
29 #include <eel/eel-glib-extensions.h>
30
31 #include "caja-query.h"
32 #include "caja-file-utilities.h"
33
34 struct CajaQueryDetails
35 {
36 char *text;
37 char *location_uri;
38 GList *mime_types;
39 GList *tags;
40 gint64 timestamp;
41 gint64 size;
42 char *contained_text;
43 };
44
45 G_DEFINE_TYPE (CajaQuery,
46 caja_query,
47 G_TYPE_OBJECT);
48
49 static GObjectClass *parent_class = NULL;
50
51 static void
finalize(GObject * object)52 finalize (GObject *object)
53 {
54 CajaQuery *query;
55
56 query = CAJA_QUERY (object);
57
58 g_free (query->details->text);
59 g_free (query->details);
60
61 EEL_CALL_PARENT (G_OBJECT_CLASS, finalize, (object));
62 }
63
64 static void
caja_query_class_init(CajaQueryClass * class)65 caja_query_class_init (CajaQueryClass *class)
66 {
67 GObjectClass *gobject_class;
68
69 parent_class = g_type_class_peek_parent (class);
70
71 gobject_class = G_OBJECT_CLASS (class);
72 gobject_class->finalize = finalize;
73 }
74
75 static void
caja_query_init(CajaQuery * query)76 caja_query_init (CajaQuery *query)
77 {
78 query->details = g_new0 (CajaQueryDetails, 1);
79 query->details->timestamp = 0;
80 query->details->size = 0;
81 }
82
83 CajaQuery *
caja_query_new(void)84 caja_query_new (void)
85 {
86 return g_object_new (CAJA_TYPE_QUERY, NULL);
87 }
88
89
90 char *
caja_query_get_text(CajaQuery * query)91 caja_query_get_text (CajaQuery *query)
92 {
93 return g_strdup (query->details->text);
94 }
95
96 void
caja_query_set_text(CajaQuery * query,const char * text)97 caja_query_set_text (CajaQuery *query, const char *text)
98 {
99 g_free (query->details->text);
100 query->details->text = g_strdup (text);
101 }
102
103 char *
caja_query_get_location(CajaQuery * query)104 caja_query_get_location (CajaQuery *query)
105 {
106 return g_strdup (query->details->location_uri);
107 }
108
109 void
caja_query_set_location(CajaQuery * query,const char * uri)110 caja_query_set_location (CajaQuery *query, const char *uri)
111 {
112 g_free (query->details->location_uri);
113 query->details->location_uri = g_strdup (uri);
114 }
115
116 GList *
caja_query_get_mime_types(CajaQuery * query)117 caja_query_get_mime_types (CajaQuery *query)
118 {
119 return g_list_copy_deep (query->details->mime_types, (GCopyFunc) g_strdup, NULL);
120 }
121
122 void
caja_query_set_mime_types(CajaQuery * query,GList * mime_types)123 caja_query_set_mime_types (CajaQuery *query, GList *mime_types)
124 {
125 g_list_free_full (query->details->mime_types, g_free);
126 query->details->mime_types = g_list_copy_deep (mime_types, (GCopyFunc) g_strdup, NULL);
127 }
128
129 void
caja_query_add_mime_type(CajaQuery * query,const char * mime_type)130 caja_query_add_mime_type (CajaQuery *query, const char *mime_type)
131 {
132 query->details->mime_types = g_list_append (query->details->mime_types,
133 g_strdup (mime_type));
134 }
135
136 GList *
caja_query_get_tags(CajaQuery * query)137 caja_query_get_tags (CajaQuery *query)
138 {
139 return g_list_copy_deep (query->details->tags, (GCopyFunc) g_strdup, NULL);
140 }
141
142 void
caja_query_set_tags(CajaQuery * query,GList * tags)143 caja_query_set_tags (CajaQuery *query, GList *tags)
144 {
145 g_list_free_full (query->details->tags, g_free);
146 query->details->tags = g_list_copy_deep (tags, (GCopyFunc) g_strdup, NULL);
147 }
148
149 void
caja_query_add_tag(CajaQuery * query,const char * tag)150 caja_query_add_tag (CajaQuery *query, const char *tag)
151 {
152 gchar *normalized = g_utf8_normalize (tag, -1, G_NORMALIZE_NFD);
153 gchar *lower_case = g_utf8_strdown (normalized, -1);
154
155 g_free (normalized);
156 query->details->tags = g_list_append (query->details->tags, lower_case);
157 }
158
159 char *
caja_query_to_readable_string(CajaQuery * query)160 caja_query_to_readable_string (CajaQuery *query)
161 {
162 if (!query || !query->details->text)
163 {
164 return g_strdup (_("Search"));
165 }
166
167 return g_strdup_printf (_("Search for \"%s\""), query->details->text);
168 }
169
170 static char *
encode_home_uri(const char * uri)171 encode_home_uri (const char *uri)
172 {
173 char *home_uri;
174 const char *encoded_uri;
175
176 home_uri = caja_get_home_directory_uri ();
177
178 if (g_str_has_prefix (uri, home_uri))
179 {
180 encoded_uri = uri + strlen (home_uri);
181 if (*encoded_uri == '/')
182 {
183 encoded_uri++;
184 }
185 }
186 else
187 {
188 encoded_uri = uri;
189 }
190
191 g_free (home_uri);
192
193 return g_markup_escape_text (encoded_uri, -1);
194 }
195
196 static char *
decode_home_uri(const char * uri)197 decode_home_uri (const char *uri)
198 {
199 char *decoded_uri;
200
201 if (g_str_has_prefix (uri, "file:"))
202 {
203 decoded_uri = g_strdup (uri);
204 }
205 else
206 {
207 char *home_uri;
208
209 home_uri = caja_get_home_directory_uri ();
210
211 decoded_uri = g_strconcat (home_uri, "/", uri, NULL);
212
213 g_free (home_uri);
214 }
215
216 return decoded_uri;
217 }
218
219
220 typedef struct
221 {
222 CajaQuery *query;
223 gboolean in_text;
224 gboolean in_location;
225 gboolean in_mimetypes;
226 gboolean in_mimetype;
227 gboolean in_tags;
228 gboolean in_tag;
229 } ParserInfo;
230
231 static void
start_element_cb(GMarkupParseContext * ctx,const char * element_name,const char ** attribute_names,const char ** attribute_values,gpointer user_data,GError ** err)232 start_element_cb (GMarkupParseContext *ctx,
233 const char *element_name,
234 const char **attribute_names,
235 const char **attribute_values,
236 gpointer user_data,
237 GError **err)
238 {
239 ParserInfo *info;
240
241 info = (ParserInfo *) user_data;
242
243 if (strcmp (element_name, "text") == 0)
244 info->in_text = TRUE;
245 else if (strcmp (element_name, "location") == 0)
246 info->in_location = TRUE;
247 else if (strcmp (element_name, "mimetypes") == 0)
248 info->in_mimetypes = TRUE;
249 else if (strcmp (element_name, "mimetype") == 0)
250 info->in_mimetype = TRUE;
251 else if (strcmp (element_name, "tags") == 0)
252 info->in_tags = TRUE;
253 else if (strcmp (element_name, "tag") == 0)
254 info->in_tag = TRUE;
255 }
256
257 static void
end_element_cb(GMarkupParseContext * ctx,const char * element_name,gpointer user_data,GError ** err)258 end_element_cb (GMarkupParseContext *ctx,
259 const char *element_name,
260 gpointer user_data,
261 GError **err)
262 {
263 ParserInfo *info;
264
265 info = (ParserInfo *) user_data;
266
267 if (strcmp (element_name, "text") == 0)
268 info->in_text = FALSE;
269 else if (strcmp (element_name, "location") == 0)
270 info->in_location = FALSE;
271 else if (strcmp (element_name, "mimetypes") == 0)
272 info->in_mimetypes = FALSE;
273 else if (strcmp (element_name, "mimetype") == 0)
274 info->in_mimetype = FALSE;
275 else if (strcmp (element_name, "tags") == 0)
276 info->in_tags = FALSE;
277 else if (strcmp (element_name, "tag") == 0)
278 info->in_tag = FALSE;
279 }
280
281 static void
text_cb(GMarkupParseContext * ctx,const char * text,gsize text_len,gpointer user_data,GError ** err)282 text_cb (GMarkupParseContext *ctx,
283 const char *text,
284 gsize text_len,
285 gpointer user_data,
286 GError **err)
287 {
288 ParserInfo *info;
289 char *t, *uri;
290
291 info = (ParserInfo *) user_data;
292
293 t = g_strndup (text, text_len);
294
295 if (info->in_text)
296 {
297 caja_query_set_text (info->query, t);
298 }
299 else if (info->in_location)
300 {
301 uri = decode_home_uri (t);
302 caja_query_set_location (info->query, uri);
303 g_free (uri);
304 }
305 else if (info->in_mimetypes && info->in_mimetype)
306 {
307 caja_query_add_mime_type (info->query, t);
308 }
309 else if (info->in_tags && info->in_tag)
310 {
311 caja_query_add_tag (info->query, t);
312 }
313
314 g_free (t);
315
316 }
317
318 static void
error_cb(GMarkupParseContext * ctx,GError * err,gpointer user_data)319 error_cb (GMarkupParseContext *ctx,
320 GError *err,
321 gpointer user_data)
322 {
323 }
324
325 static GMarkupParser parser =
326 {
327 start_element_cb,
328 end_element_cb,
329 text_cb,
330 NULL,
331 error_cb
332 };
333
334
335 static CajaQuery *
caja_query_parse_xml(char * xml,gsize xml_len)336 caja_query_parse_xml (char *xml, gsize xml_len)
337 {
338 ParserInfo info = { NULL };
339 GMarkupParseContext *ctx;
340
341 if (xml_len == -1)
342 {
343 xml_len = strlen (xml);
344 }
345
346 info.query = caja_query_new ();
347 info.in_text = FALSE;
348
349 ctx = g_markup_parse_context_new (&parser, 0, &info, NULL);
350 g_markup_parse_context_parse (ctx, xml, xml_len, NULL);
351 g_markup_parse_context_free (ctx);
352
353 return info.query;
354 }
355
356
357 CajaQuery *
caja_query_load(char * file)358 caja_query_load (char *file)
359 {
360 CajaQuery *query;
361 char *xml;
362 gsize xml_len;
363
364 if (!g_file_test (file, G_FILE_TEST_EXISTS))
365 {
366 return NULL;
367 }
368
369
370 g_file_get_contents (file, &xml, &xml_len, NULL);
371 query = caja_query_parse_xml (xml, xml_len);
372 g_free (xml);
373
374 return query;
375 }
376
377 static char *
caja_query_to_xml(CajaQuery * query)378 caja_query_to_xml (CajaQuery *query)
379 {
380 GString *xml;
381 char *text;
382 GList *l;
383
384 xml = g_string_new ("");
385 g_string_append (xml,
386 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
387 "<query version=\"1.0\">\n");
388
389 text = g_markup_escape_text (query->details->text, -1);
390 g_string_append_printf (xml, " <text>%s</text>\n", text);
391 g_free (text);
392
393 if (query->details->location_uri)
394 {
395 char *uri;
396
397 uri = encode_home_uri (query->details->location_uri);
398 g_string_append_printf (xml, " <location>%s</location>\n", uri);
399 g_free (uri);
400 }
401
402 if (query->details->mime_types)
403 {
404 g_string_append (xml, " <mimetypes>\n");
405 for (l = query->details->mime_types; l != NULL; l = l->next)
406 {
407 char *mimetype;
408
409 mimetype = g_markup_escape_text (l->data, -1);
410 g_string_append_printf (xml, " <mimetype>%s</mimetype>\n", mimetype);
411 g_free (mimetype);
412 }
413 g_string_append (xml, " </mimetypes>\n");
414 }
415
416 if (query->details->tags)
417 {
418 g_string_append (xml, " <tags>\n");
419 for (l = query->details->tags; l != NULL; l = l->next)
420 {
421 char *tag;
422
423 tag = g_markup_escape_text (l->data, -1);
424 g_string_append_printf (xml, " <tag>%s</tag>\n", tag);
425 g_free (tag);
426 }
427 g_string_append (xml, " </tags>\n");
428 }
429
430 if (query->details->timestamp != 0)
431 {
432 g_string_append_printf(xml, " <duration>%ld</duration>",
433 query->details->timestamp);
434 }
435
436 if (query->details->size != 0)
437 {
438 g_string_append_printf(xml, " <size>%ld</size>", query->details->size);
439 }
440
441 g_string_append (xml, "</query>\n");
442
443 return g_string_free (xml, FALSE);
444 }
445
446 gboolean
caja_query_save(CajaQuery * query,char * file)447 caja_query_save (CajaQuery *query, char *file)
448 {
449 char *xml;
450 GError *err = NULL;
451 gboolean res;
452
453
454 res = TRUE;
455 xml = caja_query_to_xml (query);
456 g_file_set_contents (file, xml, strlen (xml), &err);
457 g_free (xml);
458
459 if (err != NULL)
460 {
461 res = FALSE;
462 g_error_free (err);
463 }
464 return res;
465 }
466
caja_query_set_timestamp(CajaQuery * query,gint64 sec)467 void caja_query_set_timestamp(CajaQuery *query, gint64 sec)
468 {
469 query->details->timestamp = sec;
470 }
471
caja_query_get_timestamp(CajaQuery * query)472 gint64 caja_query_get_timestamp(CajaQuery *query)
473 {
474 return query->details->timestamp;
475 }
476
caja_query_set_size(CajaQuery * query,gint64 size)477 void caja_query_set_size(CajaQuery *query, gint64 size)
478 {
479 query->details->size = size;
480 }
481
caja_query_get_size(CajaQuery * query)482 gint64 caja_query_get_size(CajaQuery *query)
483 {
484 return query->details->size;
485 }
486
caja_query_set_contained_text(CajaQuery * query,const char * text)487 void caja_query_set_contained_text (CajaQuery *query, const char *text)
488 {
489 g_free (query->details->contained_text);
490 query->details->contained_text = g_strdup (text);
491 }
492
caja_query_get_contained_text(CajaQuery * query)493 char *caja_query_get_contained_text (CajaQuery *query)
494 {
495 return g_strdup (query->details->contained_text);
496 }
497