1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2 /*
3 Copyright (C) 2005 Novell, Inc
4
5 This program 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 This program 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; if not, write to the
17 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 #include <config.h>
24 #include <string.h>
25
26 #include <gtk/gtk.h>
27 #include <gio/gio.h>
28 #include <sys/time.h>
29
30 #include <eel/eel-glib-extensions.h>
31
32 #include "caja-search-directory.h"
33 #include "caja-search-directory-file.h"
34 #include "caja-directory-private.h"
35 #include "caja-file.h"
36 #include "caja-file-private.h"
37 #include "caja-file-utilities.h"
38 #include "caja-search-engine.h"
39
40 struct CajaSearchDirectoryDetails
41 {
42 CajaQuery *query;
43 char *saved_search_uri;
44 gboolean modified;
45
46 CajaSearchEngine *engine;
47
48 gboolean search_running;
49 gboolean search_finished;
50
51 GList *files;
52 GHashTable *file_hash;
53
54 GList *monitor_list;
55 GList *callback_list;
56 GList *pending_callback_list;
57 };
58
59 typedef struct
60 {
61 gboolean monitor_hidden_files;
62 CajaFileAttributes monitor_attributes;
63
64 gconstpointer client;
65 } SearchMonitor;
66
67 typedef struct
68 {
69 CajaSearchDirectory *search_directory;
70
71 CajaDirectoryCallback callback;
72 gpointer callback_data;
73
74 CajaFileAttributes wait_for_attributes;
75 gboolean wait_for_file_list;
76 GList *file_list;
77 GHashTable *non_ready_hash;
78 } SearchCallback;
79
80 G_DEFINE_TYPE (CajaSearchDirectory, caja_search_directory,
81 CAJA_TYPE_DIRECTORY);
82
83 static void search_engine_hits_added (CajaSearchEngine *engine, GList *hits, CajaSearchDirectory *search);
84 static void search_engine_hits_subtracted (CajaSearchEngine *engine, GList *hits, CajaSearchDirectory *search);
85 static void search_engine_finished (CajaSearchEngine *engine, CajaSearchDirectory *search);
86 static void search_engine_error (CajaSearchEngine *engine, const char *error, CajaSearchDirectory *search);
87 static void search_callback_file_ready_callback (CajaFile *file, gpointer data);
88 static void file_changed (CajaFile *file, CajaSearchDirectory *search);
89
90 static void
ensure_search_engine(CajaSearchDirectory * search)91 ensure_search_engine (CajaSearchDirectory *search)
92 {
93 if (!search->details->engine)
94 {
95 search->details->engine = caja_search_engine_new ();
96 g_signal_connect (search->details->engine, "hits-added",
97 G_CALLBACK (search_engine_hits_added),
98 search);
99 g_signal_connect (search->details->engine, "hits-subtracted",
100 G_CALLBACK (search_engine_hits_subtracted),
101 search);
102 g_signal_connect (search->details->engine, "finished",
103 G_CALLBACK (search_engine_finished),
104 search);
105 g_signal_connect (search->details->engine, "error",
106 G_CALLBACK (search_engine_error),
107 search);
108 }
109 }
110
111 static void
reset_file_list(CajaSearchDirectory * search)112 reset_file_list (CajaSearchDirectory *search)
113 {
114 GList *list, *monitor_list;
115 SearchMonitor *monitor;
116 CajaFile *file = NULL;
117
118 /* Remove file connections */
119 for (list = search->details->files; list != NULL; list = list->next)
120 {
121 file = list->data;
122
123 /* Disconnect change handler */
124 g_signal_handlers_disconnect_by_func (file, file_changed, search);
125
126 /* Remove monitors */
127 for (monitor_list = search->details->monitor_list; monitor_list;
128 monitor_list = monitor_list->next)
129 {
130 monitor = monitor_list->data;
131 caja_file_monitor_remove (file, monitor);
132 }
133 }
134
135 caja_file_list_free (search->details->files);
136 search->details->files = NULL;
137 }
138
139 static void
start_or_stop_search_engine(CajaSearchDirectory * search,gboolean adding)140 start_or_stop_search_engine (CajaSearchDirectory *search, gboolean adding)
141 {
142 if (adding && (search->details->monitor_list ||
143 search->details->pending_callback_list) &&
144 search->details->query &&
145 !search->details->search_running)
146 {
147 /* We need to start the search engine */
148 search->details->search_running = TRUE;
149 search->details->search_finished = FALSE;
150 ensure_search_engine (search);
151 caja_search_engine_set_query (search->details->engine, search->details->query);
152
153 reset_file_list (search);
154
155 caja_search_engine_start (search->details->engine);
156 }
157 else if (!adding && !search->details->monitor_list &&
158 !search->details->pending_callback_list &&
159 search->details->engine &&
160 search->details->search_running)
161 {
162 search->details->search_running = FALSE;
163 caja_search_engine_stop (search->details->engine);
164
165 reset_file_list (search);
166 }
167
168 }
169
170 static void
file_changed(CajaFile * file,CajaSearchDirectory * search)171 file_changed (CajaFile *file, CajaSearchDirectory *search)
172 {
173 GList list;
174
175 list.data = file;
176 list.next = NULL;
177
178 caja_directory_emit_files_changed (CAJA_DIRECTORY (search), &list);
179 }
180
181 static void
search_monitor_add(CajaDirectory * directory,gconstpointer client,gboolean monitor_hidden_files,CajaFileAttributes file_attributes,CajaDirectoryCallback callback,gpointer callback_data)182 search_monitor_add (CajaDirectory *directory,
183 gconstpointer client,
184 gboolean monitor_hidden_files,
185 CajaFileAttributes file_attributes,
186 CajaDirectoryCallback callback,
187 gpointer callback_data)
188 {
189 GList *list;
190 SearchMonitor *monitor;
191 CajaSearchDirectory *search;
192 CajaFile *file = NULL;
193
194 search = CAJA_SEARCH_DIRECTORY (directory);
195
196 monitor = g_new0 (SearchMonitor, 1);
197 monitor->monitor_hidden_files = monitor_hidden_files;
198 monitor->monitor_attributes = file_attributes;
199 monitor->client = client;
200
201 search->details->monitor_list = g_list_prepend (search->details->monitor_list, monitor);
202
203 if (callback != NULL)
204 {
205 (* callback) (directory, search->details->files, callback_data);
206 }
207
208 for (list = search->details->files; list != NULL; list = list->next)
209 {
210 file = list->data;
211
212 /* Add monitors */
213 caja_file_monitor_add (file, monitor, file_attributes);
214 }
215
216 start_or_stop_search_engine (search, TRUE);
217 }
218
219 static void
search_monitor_remove_file_monitors(SearchMonitor * monitor,CajaSearchDirectory * search)220 search_monitor_remove_file_monitors (SearchMonitor *monitor, CajaSearchDirectory *search)
221 {
222 GList *list;
223 CajaFile *file = NULL;
224
225 for (list = search->details->files; list != NULL; list = list->next)
226 {
227 file = list->data;
228
229 caja_file_monitor_remove (file, monitor);
230 }
231 }
232
233 static void
search_monitor_destroy(SearchMonitor * monitor,CajaSearchDirectory * search)234 search_monitor_destroy (SearchMonitor *monitor, CajaSearchDirectory *search)
235 {
236 search_monitor_remove_file_monitors (monitor, search);
237
238 g_free (monitor);
239 }
240
241 static void
search_monitor_remove(CajaDirectory * directory,gconstpointer client)242 search_monitor_remove (CajaDirectory *directory,
243 gconstpointer client)
244 {
245 CajaSearchDirectory *search;
246 GList *list;
247 SearchMonitor *monitor = NULL;
248
249 search = CAJA_SEARCH_DIRECTORY (directory);
250
251 for (list = search->details->monitor_list; list != NULL; list = list->next)
252 {
253 monitor = list->data;
254
255 if (monitor->client == client)
256 {
257 search->details->monitor_list = g_list_delete_link (search->details->monitor_list, list);
258
259 search_monitor_destroy (monitor, search);
260
261 break;
262 }
263 }
264
265 start_or_stop_search_engine (search, FALSE);
266 }
267
268 static void
cancel_call_when_ready(gpointer key,gpointer value,gpointer user_data)269 cancel_call_when_ready (gpointer key, gpointer value, gpointer user_data)
270 {
271 SearchCallback *search_callback;
272 CajaFile *file;
273
274 file = key;
275 search_callback = user_data;
276
277 caja_file_cancel_call_when_ready (file, search_callback_file_ready_callback,
278 search_callback);
279 }
280
281 static void
search_callback_destroy(SearchCallback * search_callback)282 search_callback_destroy (SearchCallback *search_callback)
283 {
284 if (search_callback->non_ready_hash)
285 {
286 g_hash_table_foreach (search_callback->non_ready_hash, cancel_call_when_ready, search_callback);
287 g_hash_table_destroy (search_callback->non_ready_hash);
288 }
289
290 caja_file_list_free (search_callback->file_list);
291
292 g_free (search_callback);
293 }
294
295 static void
search_callback_invoke_and_destroy(SearchCallback * search_callback)296 search_callback_invoke_and_destroy (SearchCallback *search_callback)
297 {
298 search_callback->callback (CAJA_DIRECTORY (search_callback->search_directory),
299 search_callback->file_list,
300 search_callback->callback_data);
301
302 search_callback->search_directory->details->callback_list =
303 g_list_remove (search_callback->search_directory->details->callback_list, search_callback);
304
305 search_callback_destroy (search_callback);
306 }
307
308 static void
search_callback_file_ready_callback(CajaFile * file,gpointer data)309 search_callback_file_ready_callback (CajaFile *file, gpointer data)
310 {
311 SearchCallback *search_callback = data;
312
313 g_hash_table_remove (search_callback->non_ready_hash, file);
314
315 if (g_hash_table_size (search_callback->non_ready_hash) == 0)
316 {
317 search_callback_invoke_and_destroy (search_callback);
318 }
319 }
320
321 static void
search_callback_add_file_callbacks(SearchCallback * callback)322 search_callback_add_file_callbacks (SearchCallback *callback)
323 {
324 GList *file_list_copy, *list;
325 CajaFile *file = NULL;
326
327 file_list_copy = g_list_copy (callback->file_list);
328
329 for (list = file_list_copy; list != NULL; list = list->next)
330 {
331 file = list->data;
332
333 caja_file_call_when_ready (file,
334 callback->wait_for_attributes,
335 search_callback_file_ready_callback,
336 callback);
337 }
338 g_list_free (file_list_copy);
339 }
340
341 static SearchCallback *
search_callback_find(CajaSearchDirectory * search,CajaDirectoryCallback callback,gpointer callback_data)342 search_callback_find (CajaSearchDirectory *search, CajaDirectoryCallback callback, gpointer callback_data)
343 {
344 GList *list;
345 SearchCallback *search_callback = NULL;
346
347 for (list = search->details->callback_list; list != NULL; list = list->next)
348 {
349 search_callback = list->data;
350
351 if (search_callback->callback == callback &&
352 search_callback->callback_data == callback_data)
353 {
354 return search_callback;
355 }
356 }
357
358 return NULL;
359 }
360
361 static SearchCallback *
search_callback_find_pending(CajaSearchDirectory * search,CajaDirectoryCallback callback,gpointer callback_data)362 search_callback_find_pending (CajaSearchDirectory *search, CajaDirectoryCallback callback, gpointer callback_data)
363 {
364 GList *list;
365 SearchCallback *search_callback = NULL;
366
367 for (list = search->details->pending_callback_list; list != NULL; list = list->next)
368 {
369 search_callback = list->data;
370
371 if (search_callback->callback == callback &&
372 search_callback->callback_data == callback_data)
373 {
374 return search_callback;
375 }
376 }
377
378 return NULL;
379 }
380
381 static GHashTable *
file_list_to_hash_table(GList * file_list)382 file_list_to_hash_table (GList *file_list)
383 {
384 GList *list;
385 GHashTable *table;
386
387 if (!file_list)
388 return NULL;
389
390 table = g_hash_table_new (NULL, NULL);
391
392 for (list = file_list; list != NULL; list = list->next)
393 {
394 g_hash_table_insert (table, list->data, list->data);
395 }
396
397 return table;
398 }
399
400 static void
search_call_when_ready(CajaDirectory * directory,CajaFileAttributes file_attributes,gboolean wait_for_file_list,CajaDirectoryCallback callback,gpointer callback_data)401 search_call_when_ready (CajaDirectory *directory,
402 CajaFileAttributes file_attributes,
403 gboolean wait_for_file_list,
404 CajaDirectoryCallback callback,
405 gpointer callback_data)
406 {
407 CajaSearchDirectory *search;
408 SearchCallback *search_callback;
409
410 search = CAJA_SEARCH_DIRECTORY (directory);
411
412 search_callback = search_callback_find (search, callback, callback_data);
413 if (search_callback == NULL)
414 {
415 search_callback = search_callback_find_pending (search, callback, callback_data);
416 }
417
418 if (search_callback)
419 {
420 g_warning ("tried to add a new callback while an old one was pending");
421 return;
422 }
423
424 search_callback = g_new0 (SearchCallback, 1);
425 search_callback->search_directory = search;
426 search_callback->callback = callback;
427 search_callback->callback_data = callback_data;
428 search_callback->wait_for_attributes = file_attributes;
429 search_callback->wait_for_file_list = wait_for_file_list;
430
431 if (wait_for_file_list && !search->details->search_finished)
432 {
433 /* Add it to the pending callback list, which will be
434 * processed when the directory has finished loading
435 */
436 search->details->pending_callback_list =
437 g_list_prepend (search->details->pending_callback_list, search_callback);
438
439 /* We might need to start the search engine */
440 start_or_stop_search_engine (search, TRUE);
441 }
442 else
443 {
444 search_callback->file_list = caja_file_list_copy (search->details->files);
445 search_callback->non_ready_hash = file_list_to_hash_table (search->details->files);
446
447 if (!search_callback->non_ready_hash)
448 {
449 /* If there are no ready files, we invoke the callback
450 with an empty list.
451 */
452 search_callback_invoke_and_destroy (search_callback);
453 }
454 else
455 {
456 search->details->callback_list = g_list_prepend (search->details->callback_list, search_callback);
457 search_callback_add_file_callbacks (search_callback);
458 }
459 }
460 }
461
462 static void
search_cancel_callback(CajaDirectory * directory,CajaDirectoryCallback callback,gpointer callback_data)463 search_cancel_callback (CajaDirectory *directory,
464 CajaDirectoryCallback callback,
465 gpointer callback_data)
466 {
467 CajaSearchDirectory *search;
468 SearchCallback *search_callback;
469
470 search = CAJA_SEARCH_DIRECTORY (directory);
471 search_callback = search_callback_find (search, callback, callback_data);
472
473 if (search_callback)
474 {
475 search->details->callback_list = g_list_remove (search->details->callback_list, search_callback);
476
477 search_callback_destroy (search_callback);
478
479 return;
480 }
481
482 /* Check for a pending callback */
483 search_callback = search_callback_find_pending (search, callback, callback_data);
484
485 if (search_callback)
486 {
487 search->details->pending_callback_list = g_list_remove (search->details->pending_callback_list, search_callback);
488
489 search_callback_destroy (search_callback);
490
491 /* We might need to stop the search engine now */
492 start_or_stop_search_engine (search, FALSE);
493 }
494 }
495
496
497 static void
search_engine_hits_added(CajaSearchEngine * engine,GList * hits,CajaSearchDirectory * search)498 search_engine_hits_added (CajaSearchEngine *engine, GList *hits,
499 CajaSearchDirectory *search)
500 {
501 GList *hit_list;
502 GList *file_list;
503 CajaFile *file;
504 SearchMonitor *monitor;
505 GList *monitor_list;
506
507 file_list = NULL;
508
509 for (hit_list = hits; hit_list != NULL; hit_list = hit_list->next)
510 {
511 char *uri;
512
513 uri = hit_list->data;
514
515 if (g_str_has_suffix (uri, CAJA_SAVED_SEARCH_EXTENSION))
516 {
517 /* Never return saved searches themselves as hits */
518 continue;
519 }
520
521 file = caja_file_get_by_uri (uri);
522
523 for (monitor_list = search->details->monitor_list; monitor_list; monitor_list = monitor_list->next)
524 {
525 monitor = monitor_list->data;
526
527 /* Add monitors */
528 caja_file_monitor_add (file, monitor, monitor->monitor_attributes);
529 }
530
531 g_signal_connect (file, "changed", G_CALLBACK (file_changed), search);
532
533 file_list = g_list_prepend (file_list, file);
534 }
535
536 search->details->files = g_list_concat (search->details->files, file_list);
537
538 caja_directory_emit_files_added (CAJA_DIRECTORY (search), file_list);
539
540 file = caja_directory_get_corresponding_file (CAJA_DIRECTORY (search));
541 caja_file_emit_changed (file);
542 caja_file_unref (file);
543 }
544
545 static void
search_engine_hits_subtracted(CajaSearchEngine * engine,GList * hits,CajaSearchDirectory * search)546 search_engine_hits_subtracted (CajaSearchEngine *engine, GList *hits,
547 CajaSearchDirectory *search)
548 {
549 GList *hit_list;
550 GList *monitor_list;
551 SearchMonitor *monitor;
552 GList *file_list;
553 CajaFile *file;
554
555 file_list = NULL;
556
557 for (hit_list = hits; hit_list != NULL; hit_list = hit_list->next)
558 {
559 char *uri;
560
561 uri = hit_list->data;
562 file = caja_file_get_by_uri (uri);
563
564 for (monitor_list = search->details->monitor_list; monitor_list;
565 monitor_list = monitor_list->next)
566 {
567 monitor = monitor_list->data;
568 /* Remove monitors */
569 caja_file_monitor_remove (file, monitor);
570 }
571
572 g_signal_handlers_disconnect_by_func (file, file_changed, search);
573
574 search->details->files = g_list_remove (search->details->files, file);
575
576 file_list = g_list_prepend (file_list, file);
577 }
578
579 caja_directory_emit_files_changed (CAJA_DIRECTORY (search), file_list);
580
581 caja_file_list_free (file_list);
582
583 file = caja_directory_get_corresponding_file (CAJA_DIRECTORY (search));
584 caja_file_emit_changed (file);
585 caja_file_unref (file);
586 }
587
588 static void
search_callback_add_pending_file_callbacks(SearchCallback * callback)589 search_callback_add_pending_file_callbacks (SearchCallback *callback)
590 {
591 callback->file_list = caja_file_list_copy (callback->search_directory->details->files);
592 callback->non_ready_hash = file_list_to_hash_table (callback->search_directory->details->files);
593
594 search_callback_add_file_callbacks (callback);
595 }
596
597 static void
search_engine_error(CajaSearchEngine * engine,const char * error_message,CajaSearchDirectory * search)598 search_engine_error (CajaSearchEngine *engine, const char *error_message, CajaSearchDirectory *search)
599 {
600 GError *error;
601
602 error = g_error_new_literal (G_IO_ERROR, G_IO_ERROR_FAILED,
603 error_message);
604 caja_directory_emit_load_error (CAJA_DIRECTORY (search),
605 error);
606 g_error_free (error);
607 }
608
609 static void
search_engine_finished(CajaSearchEngine * engine,CajaSearchDirectory * search)610 search_engine_finished (CajaSearchEngine *engine, CajaSearchDirectory *search)
611 {
612 search->details->search_finished = TRUE;
613
614 caja_directory_emit_done_loading (CAJA_DIRECTORY (search));
615
616 /* Add all file callbacks */
617 g_list_foreach (search->details->pending_callback_list,
618 (GFunc)search_callback_add_pending_file_callbacks, NULL);
619 search->details->callback_list = g_list_concat (search->details->callback_list,
620 search->details->pending_callback_list);
621
622 g_list_free (search->details->pending_callback_list);
623 search->details->pending_callback_list = NULL;
624 }
625
626 static void
search_force_reload(CajaDirectory * directory)627 search_force_reload (CajaDirectory *directory)
628 {
629 CajaSearchDirectory *search;
630
631 search = CAJA_SEARCH_DIRECTORY (directory);
632
633 if (!search->details->query)
634 {
635 return;
636 }
637
638 search->details->search_finished = FALSE;
639
640 if (!search->details->engine)
641 {
642 return;
643 }
644
645 /* Remove file monitors */
646 reset_file_list (search);
647
648 if (search->details->search_running)
649 {
650 caja_search_engine_stop (search->details->engine);
651 caja_search_engine_set_query (search->details->engine, search->details->query);
652 caja_search_engine_start (search->details->engine);
653 }
654 }
655
656 static gboolean
search_are_all_files_seen(CajaDirectory * directory)657 search_are_all_files_seen (CajaDirectory *directory)
658 {
659 CajaSearchDirectory *search;
660
661 search = CAJA_SEARCH_DIRECTORY (directory);
662
663 return (!search->details->query ||
664 search->details->search_finished);
665 }
666
667 static gboolean
search_contains_file(CajaDirectory * directory,CajaFile * file)668 search_contains_file (CajaDirectory *directory,
669 CajaFile *file)
670 {
671 CajaSearchDirectory *search;
672
673 search = CAJA_SEARCH_DIRECTORY (directory);
674
675 /* FIXME: Maybe put the files in a hash */
676 return (g_list_find (search->details->files, file) != NULL);
677 }
678
679 static GList *
search_get_file_list(CajaDirectory * directory)680 search_get_file_list (CajaDirectory *directory)
681 {
682 CajaSearchDirectory *search;
683
684 search = CAJA_SEARCH_DIRECTORY (directory);
685
686 return caja_file_list_copy (search->details->files);
687 }
688
689
690 static gboolean
search_is_editable(CajaDirectory * directory)691 search_is_editable (CajaDirectory *directory)
692 {
693 return FALSE;
694 }
695
696 static void
search_dispose(GObject * object)697 search_dispose (GObject *object)
698 {
699 CajaSearchDirectory *search;
700 GList *list;
701
702 search = CAJA_SEARCH_DIRECTORY (object);
703
704 /* Remove search monitors */
705 if (search->details->monitor_list)
706 {
707 for (list = search->details->monitor_list; list != NULL; list = list->next)
708 {
709 search_monitor_destroy ((SearchMonitor *)list->data, search);
710 }
711
712 g_list_free (search->details->monitor_list);
713 search->details->monitor_list = NULL;
714 }
715
716 reset_file_list (search);
717
718 if (search->details->callback_list)
719 {
720 /* Remove callbacks */
721 g_list_foreach (search->details->callback_list,
722 (GFunc)search_callback_destroy, NULL);
723 g_list_free (search->details->callback_list);
724 search->details->callback_list = NULL;
725 }
726
727 if (search->details->pending_callback_list)
728 {
729 g_list_foreach (search->details->pending_callback_list,
730 (GFunc)search_callback_destroy, NULL);
731 g_list_free (search->details->pending_callback_list);
732 search->details->pending_callback_list = NULL;
733 }
734
735 if (search->details->query)
736 {
737 g_object_unref (search->details->query);
738 search->details->query = NULL;
739 }
740
741 if (search->details->engine)
742 {
743 if (search->details->search_running)
744 {
745 caja_search_engine_stop (search->details->engine);
746 }
747
748 g_object_unref (search->details->engine);
749 search->details->engine = NULL;
750 }
751
752 G_OBJECT_CLASS (caja_search_directory_parent_class)->dispose (object);
753 }
754
755 static void
search_finalize(GObject * object)756 search_finalize (GObject *object)
757 {
758 CajaSearchDirectory *search;
759
760 search = CAJA_SEARCH_DIRECTORY (object);
761
762 g_free (search->details->saved_search_uri);
763
764 g_free (search->details);
765
766 G_OBJECT_CLASS (caja_search_directory_parent_class)->finalize (object);
767 }
768
769 static void
caja_search_directory_init(CajaSearchDirectory * search)770 caja_search_directory_init (CajaSearchDirectory *search)
771 {
772 search->details = g_new0 (CajaSearchDirectoryDetails, 1);
773 }
774
775 static void
caja_search_directory_class_init(CajaSearchDirectoryClass * class)776 caja_search_directory_class_init (CajaSearchDirectoryClass *class)
777 {
778 CajaDirectoryClass *directory_class;
779
780 G_OBJECT_CLASS (class)->dispose = search_dispose;
781 G_OBJECT_CLASS (class)->finalize = search_finalize;
782
783 directory_class = CAJA_DIRECTORY_CLASS (class);
784
785 directory_class->are_all_files_seen = search_are_all_files_seen;
786 directory_class->contains_file = search_contains_file;
787 directory_class->force_reload = search_force_reload;
788 directory_class->call_when_ready = search_call_when_ready;
789 directory_class->cancel_callback = search_cancel_callback;
790
791 directory_class->file_monitor_add = search_monitor_add;
792 directory_class->file_monitor_remove = search_monitor_remove;
793
794 directory_class->get_file_list = search_get_file_list;
795 directory_class->is_editable = search_is_editable;
796 }
797
798 char *
caja_search_directory_generate_new_uri(void)799 caja_search_directory_generate_new_uri (void)
800 {
801 static int counter = 0;
802 char *uri;
803
804 uri = g_strdup_printf (EEL_SEARCH_URI"//%d/", counter++);
805
806 return uri;
807 }
808
809
810 void
caja_search_directory_set_query(CajaSearchDirectory * search,CajaQuery * query)811 caja_search_directory_set_query (CajaSearchDirectory *search,
812 CajaQuery *query)
813 {
814 CajaDirectory *dir;
815 CajaFile *as_file;
816
817 if (search->details->query != query)
818 {
819 search->details->modified = TRUE;
820 }
821
822 if (query)
823 {
824 g_object_ref (query);
825 }
826
827 if (search->details->query)
828 {
829 g_object_unref (search->details->query);
830 }
831
832 search->details->query = query;
833
834 dir = CAJA_DIRECTORY (search);
835 as_file = dir->details->as_file;
836 if (as_file != NULL)
837 {
838 caja_search_directory_file_update_display_name (CAJA_SEARCH_DIRECTORY_FILE (as_file));
839 }
840 }
841
842 CajaQuery *
caja_search_directory_get_query(CajaSearchDirectory * search)843 caja_search_directory_get_query (CajaSearchDirectory *search)
844 {
845 if (search->details->query != NULL)
846 {
847 return g_object_ref (search->details->query);
848 }
849
850 return NULL;
851 }
852
853 CajaSearchDirectory *
caja_search_directory_new_from_saved_search(const char * uri)854 caja_search_directory_new_from_saved_search (const char *uri)
855 {
856 CajaSearchDirectory *search;
857 char *file;
858
859 search = CAJA_SEARCH_DIRECTORY (g_object_new (CAJA_TYPE_SEARCH_DIRECTORY, NULL));
860
861 search->details->saved_search_uri = g_strdup (uri);
862
863 file = g_filename_from_uri (uri, NULL, NULL);
864 if (file != NULL)
865 {
866 CajaQuery *query;
867
868 query = caja_query_load (file);
869 if (query != NULL)
870 {
871 caja_search_directory_set_query (search, query);
872 g_object_unref (query);
873 }
874 g_free (file);
875 }
876 else
877 {
878 g_warning ("Non-local saved searches not supported");
879 }
880
881 search->details->modified = FALSE;
882 return search;
883 }
884
885 gboolean
caja_search_directory_is_saved_search(CajaSearchDirectory * search)886 caja_search_directory_is_saved_search (CajaSearchDirectory *search)
887 {
888 return search->details->saved_search_uri != NULL;
889 }
890
891 gboolean
caja_search_directory_is_modified(CajaSearchDirectory * search)892 caja_search_directory_is_modified (CajaSearchDirectory *search)
893 {
894 return search->details->modified;
895 }
896
897 gboolean
caja_search_directory_is_indexed(CajaSearchDirectory * search)898 caja_search_directory_is_indexed (CajaSearchDirectory *search)
899 {
900 ensure_search_engine (search);
901 return caja_search_engine_is_indexed (search->details->engine);
902 }
903
904
905 void
caja_search_directory_save_to_file(CajaSearchDirectory * search,const char * save_file_uri)906 caja_search_directory_save_to_file (CajaSearchDirectory *search,
907 const char *save_file_uri)
908 {
909 char *file;
910
911 file = g_filename_from_uri (save_file_uri, NULL, NULL);
912 if (file == NULL)
913 {
914 return;
915 }
916
917 if (search->details->query != NULL)
918 {
919 caja_query_save (search->details->query, file);
920 }
921
922 g_free (file);
923 }
924
925 void
caja_search_directory_save_search(CajaSearchDirectory * search)926 caja_search_directory_save_search (CajaSearchDirectory *search)
927 {
928 if (search->details->saved_search_uri == NULL)
929 {
930 return;
931 }
932
933 caja_search_directory_save_to_file (search,
934 search->details->saved_search_uri);
935 search->details->modified = FALSE;
936 }
937