1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*-
2
3 caja-directory.c: Caja directory model.
4
5 Copyright (C) 1999, 2000, 2001 Eazel, Inc.
6
7 This program is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public License as
9 published by the Free Software Foundation; either version 2 of the
10 License, or (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
16
17 You should have received a copy of the GNU General Public
18 License along with this program; if not, write to the
19 Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
20 Boston, MA 02110-1301, USA.
21
22 Author: Darin Adler <darin@bentspoon.com>
23 */
24
25 #include <config.h>
26 #include <gtk/gtk.h>
27 #include <string.h>
28
29 #include <eel/eel-glib-extensions.h>
30 #include <eel/eel-gtk-macros.h>
31
32 #include "caja-directory-private.h"
33 #include "caja-directory-notify.h"
34 #include "caja-file-attributes.h"
35 #include "caja-file-private.h"
36 #include "caja-file-utilities.h"
37 #include "caja-search-directory.h"
38 #include "caja-global-preferences.h"
39 #include "caja-lib-self-check-functions.h"
40 #include "caja-metadata.h"
41 #include "caja-desktop-directory.h"
42 #include "caja-vfs-directory.h"
43
44 enum
45 {
46 FILES_ADDED,
47 FILES_CHANGED,
48 DONE_LOADING,
49 LOAD_ERROR,
50 LAST_SIGNAL
51 };
52
53 static guint signals[LAST_SIGNAL] = { 0 };
54
55 static GHashTable *directories;
56
57 static void caja_directory_finalize (GObject *object);
58 static CajaDirectory *caja_directory_new (GFile *location);
59 static char * real_get_name_for_self_as_new_file (CajaDirectory *directory);
60 static GList * real_get_file_list (CajaDirectory *directory);
61 static gboolean real_is_editable (CajaDirectory *directory);
62 static void set_directory_location (CajaDirectory *directory,
63 GFile *location);
64
G_DEFINE_TYPE_WITH_PRIVATE(CajaDirectory,caja_directory,G_TYPE_OBJECT)65 G_DEFINE_TYPE_WITH_PRIVATE (CajaDirectory, caja_directory, G_TYPE_OBJECT)
66
67 static void
68 caja_directory_class_init (CajaDirectoryClass *klass)
69 {
70 GObjectClass *object_class;
71
72 object_class = G_OBJECT_CLASS (klass);
73
74 object_class->finalize = caja_directory_finalize;
75
76 signals[FILES_ADDED] =
77 g_signal_new ("files_added",
78 G_TYPE_FROM_CLASS (object_class),
79 G_SIGNAL_RUN_LAST,
80 G_STRUCT_OFFSET (CajaDirectoryClass, files_added),
81 NULL, NULL,
82 g_cclosure_marshal_VOID__POINTER,
83 G_TYPE_NONE, 1, G_TYPE_POINTER);
84 signals[FILES_CHANGED] =
85 g_signal_new ("files_changed",
86 G_TYPE_FROM_CLASS (object_class),
87 G_SIGNAL_RUN_LAST,
88 G_STRUCT_OFFSET (CajaDirectoryClass, files_changed),
89 NULL, NULL,
90 g_cclosure_marshal_VOID__POINTER,
91 G_TYPE_NONE, 1, G_TYPE_POINTER);
92 signals[DONE_LOADING] =
93 g_signal_new ("done_loading",
94 G_TYPE_FROM_CLASS (object_class),
95 G_SIGNAL_RUN_LAST,
96 G_STRUCT_OFFSET (CajaDirectoryClass, done_loading),
97 NULL, NULL,
98 g_cclosure_marshal_VOID__VOID,
99 G_TYPE_NONE, 0);
100 signals[LOAD_ERROR] =
101 g_signal_new ("load_error",
102 G_TYPE_FROM_CLASS (object_class),
103 G_SIGNAL_RUN_LAST,
104 G_STRUCT_OFFSET (CajaDirectoryClass, load_error),
105 NULL, NULL,
106 g_cclosure_marshal_VOID__POINTER,
107 G_TYPE_NONE, 1, G_TYPE_POINTER);
108
109 klass->get_name_for_self_as_new_file = real_get_name_for_self_as_new_file;
110 klass->get_file_list = real_get_file_list;
111 klass->is_editable = real_is_editable;
112 }
113
114 static void
caja_directory_init(CajaDirectory * directory)115 caja_directory_init (CajaDirectory *directory)
116 {
117 directory->details = caja_directory_get_instance_private (directory);
118 directory->details->file_hash = g_hash_table_new (g_str_hash, g_str_equal);
119 directory->details->high_priority_queue = caja_file_queue_new ();
120 directory->details->low_priority_queue = caja_file_queue_new ();
121 directory->details->extension_queue = caja_file_queue_new ();
122 directory->details->free_space = (guint64)-1;
123 }
124
125 CajaDirectory *
caja_directory_ref(CajaDirectory * directory)126 caja_directory_ref (CajaDirectory *directory)
127 {
128 if (directory == NULL)
129 {
130 return directory;
131 }
132
133 g_return_val_if_fail (CAJA_IS_DIRECTORY (directory), NULL);
134
135 g_object_ref (directory);
136 return directory;
137 }
138
139 void
caja_directory_unref(CajaDirectory * directory)140 caja_directory_unref (CajaDirectory *directory)
141 {
142 if (directory == NULL)
143 {
144 return;
145 }
146
147 g_return_if_fail (CAJA_IS_DIRECTORY (directory));
148
149 g_object_unref (directory);
150 }
151
152 static void
caja_directory_finalize(GObject * object)153 caja_directory_finalize (GObject *object)
154 {
155 CajaDirectory *directory;
156
157 directory = CAJA_DIRECTORY (object);
158
159 g_hash_table_remove (directories, directory->details->location);
160
161 caja_directory_cancel (directory);
162 g_assert (directory->details->count_in_progress == NULL);
163 g_assert (directory->details->top_left_read_state == NULL);
164
165 if (directory->details->monitor_list != NULL)
166 {
167 g_warning ("destroying a CajaDirectory while it's being monitored");
168 g_list_free_full (directory->details->monitor_list, g_free);
169 }
170
171 if (directory->details->monitor != NULL)
172 {
173 caja_monitor_cancel (directory->details->monitor);
174 }
175
176 if (directory->details->dequeue_pending_idle_id != 0)
177 {
178 g_source_remove (directory->details->dequeue_pending_idle_id);
179 }
180
181 if (directory->details->call_ready_idle_id != 0)
182 {
183 g_source_remove (directory->details->call_ready_idle_id);
184 }
185
186 if (directory->details->location)
187 {
188 g_object_unref (directory->details->location);
189 }
190
191 g_assert (directory->details->file_list == NULL);
192 g_hash_table_destroy (directory->details->file_hash);
193
194 caja_file_queue_destroy (directory->details->high_priority_queue);
195 caja_file_queue_destroy (directory->details->low_priority_queue);
196 caja_file_queue_destroy (directory->details->extension_queue);
197 g_assert (directory->details->directory_load_in_progress == NULL);
198 g_assert (directory->details->count_in_progress == NULL);
199 g_assert (directory->details->dequeue_pending_idle_id == 0);
200 g_list_free_full (directory->details->pending_file_info, g_object_unref);
201
202 G_OBJECT_CLASS (caja_directory_parent_class)->finalize (object);
203 }
204
205 void
emit_change_signals_for_all_files(CajaDirectory * directory)206 emit_change_signals_for_all_files (CajaDirectory *directory)
207 {
208 GList *files;
209
210 files = g_list_copy (directory->details->file_list);
211 if (directory->details->as_file != NULL)
212 {
213 files = g_list_prepend (files, directory->details->as_file);
214 }
215
216 caja_file_list_ref (files);
217 caja_directory_emit_change_signals (directory, files);
218
219 caja_file_list_free (files);
220 }
221
222 static void
collect_all_directories(gpointer key,gpointer value,gpointer callback_data)223 collect_all_directories (gpointer key, gpointer value, gpointer callback_data)
224 {
225 CajaDirectory *directory;
226 GList **dirs;
227
228 directory = CAJA_DIRECTORY (value);
229 dirs = callback_data;
230
231 *dirs = g_list_prepend (*dirs, caja_directory_ref (directory));
232 }
233
234 void
emit_change_signals_for_all_files_in_all_directories(void)235 emit_change_signals_for_all_files_in_all_directories (void)
236 {
237 GList *dirs, *l;
238 CajaDirectory *directory = NULL;
239
240 dirs = NULL;
241 g_hash_table_foreach (directories,
242 collect_all_directories,
243 &dirs);
244
245 for (l = dirs; l != NULL; l = l->next)
246 {
247 directory = CAJA_DIRECTORY (l->data);
248 emit_change_signals_for_all_files (directory);
249 caja_directory_unref (directory);
250 }
251
252 g_list_free (dirs);
253 }
254
255 /**
256 * caja_directory_get_by_uri:
257 * @uri: URI of directory to get.
258 *
259 * Get a directory given a uri.
260 * Creates the appropriate subclass given the uri mappings.
261 * Returns a referenced object, not a floating one. Unref when finished.
262 * If two windows are viewing the same uri, the directory object is shared.
263 */
264 CajaDirectory *
caja_directory_get_internal(GFile * location,gboolean create)265 caja_directory_get_internal (GFile *location, gboolean create)
266 {
267 CajaDirectory *directory;
268
269 /* Create the hash table first time through. */
270 if (directories == NULL) {
271 directories = g_hash_table_new (g_file_hash, (GCompareFunc) g_file_equal);
272 caja_global_preferences_init ();
273 }
274
275 /* If the object is already in the hash table, look it up. */
276
277 directory = g_hash_table_lookup (directories,
278 location);
279 if (directory != NULL)
280 {
281 caja_directory_ref (directory);
282 }
283 else if (create)
284 {
285 /* Create a new directory object instead. */
286 directory = caja_directory_new (location);
287 if (directory == NULL)
288 {
289 return NULL;
290 }
291
292 /* Put it in the hash table. */
293 g_hash_table_insert (directories,
294 directory->details->location,
295 directory);
296 }
297
298 return directory;
299 }
300
301 CajaDirectory *
caja_directory_get(GFile * location)302 caja_directory_get (GFile *location)
303 {
304 if (location == NULL)
305 {
306 return NULL;
307 }
308
309 return caja_directory_get_internal (location, TRUE);
310 }
311
312 CajaDirectory *
caja_directory_get_existing(GFile * location)313 caja_directory_get_existing (GFile *location)
314 {
315 if (location == NULL)
316 {
317 return NULL;
318 }
319
320 return caja_directory_get_internal (location, FALSE);
321 }
322
323
324 CajaDirectory *
caja_directory_get_by_uri(const char * uri)325 caja_directory_get_by_uri (const char *uri)
326 {
327 CajaDirectory *directory;
328 GFile *location;
329
330 if (uri == NULL)
331 {
332 return NULL;
333 }
334
335 location = g_file_new_for_uri (uri);
336
337 directory = caja_directory_get_internal (location, TRUE);
338 g_object_unref (location);
339 return directory;
340 }
341
342 CajaDirectory *
caja_directory_get_for_file(CajaFile * file)343 caja_directory_get_for_file (CajaFile *file)
344 {
345 char *uri;
346 CajaDirectory *directory;
347
348 g_return_val_if_fail (CAJA_IS_FILE (file), NULL);
349
350 uri = caja_file_get_uri (file);
351 directory = caja_directory_get_by_uri (uri);
352 g_free (uri);
353 return directory;
354 }
355
356 /* Returns a reffed CajaFile object for this directory.
357 */
358 CajaFile *
caja_directory_get_corresponding_file(CajaDirectory * directory)359 caja_directory_get_corresponding_file (CajaDirectory *directory)
360 {
361 CajaFile *file;
362
363 file = caja_directory_get_existing_corresponding_file (directory);
364 if (file == NULL)
365 {
366 char *uri;
367
368 uri = caja_directory_get_uri (directory);
369 file = caja_file_get_by_uri (uri);
370 g_free (uri);
371 }
372
373 return file;
374 }
375
376 /* Returns a reffed CajaFile object for this directory, but only if the
377 * CajaFile object has already been created.
378 */
379 CajaFile *
caja_directory_get_existing_corresponding_file(CajaDirectory * directory)380 caja_directory_get_existing_corresponding_file (CajaDirectory *directory)
381 {
382 CajaFile *file;
383 char *uri;
384
385 file = directory->details->as_file;
386 if (file != NULL)
387 {
388 caja_file_ref (file);
389 return file;
390 }
391
392 uri = caja_directory_get_uri (directory);
393 file = caja_file_get_existing_by_uri (uri);
394 g_free (uri);
395 return file;
396 }
397
398 /* caja_directory_get_name_for_self_as_new_file:
399 *
400 * Get a name to display for the file representing this
401 * directory. This is called only when there's no VFS
402 * directory for this CajaDirectory.
403 */
404 char *
caja_directory_get_name_for_self_as_new_file(CajaDirectory * directory)405 caja_directory_get_name_for_self_as_new_file (CajaDirectory *directory)
406 {
407 g_return_val_if_fail (CAJA_IS_DIRECTORY (directory), NULL);
408
409 if (CAJA_DIRECTORY_GET_CLASS(directory)->get_name_for_self_as_new_file == NULL)
410 return NULL;
411 else
412 return CAJA_DIRECTORY_GET_CLASS(directory)->get_name_for_self_as_new_file (directory);
413 }
414
415 static char *
real_get_name_for_self_as_new_file(CajaDirectory * directory)416 real_get_name_for_self_as_new_file (CajaDirectory *directory)
417 {
418 char *directory_uri;
419 char *name, *colon;
420
421 directory_uri = caja_directory_get_uri (directory);
422
423 colon = strchr (directory_uri, ':');
424 if (colon == NULL || colon == directory_uri)
425 {
426 name = g_strdup (directory_uri);
427 }
428 else
429 {
430 name = g_strndup (directory_uri, colon - directory_uri);
431 }
432 g_free (directory_uri);
433
434 return name;
435 }
436
437 char *
caja_directory_get_uri(CajaDirectory * directory)438 caja_directory_get_uri (CajaDirectory *directory)
439 {
440 g_return_val_if_fail (CAJA_IS_DIRECTORY (directory), NULL);
441
442 return g_file_get_uri (directory->details->location);
443 }
444
445 GFile *
caja_directory_get_location(CajaDirectory * directory)446 caja_directory_get_location (CajaDirectory *directory)
447 {
448 g_return_val_if_fail (CAJA_IS_DIRECTORY (directory), NULL);
449
450 return g_object_ref (directory->details->location);
451 }
452
453 static CajaDirectory *
caja_directory_new(GFile * location)454 caja_directory_new (GFile *location)
455 {
456 CajaDirectory *directory;
457 char *uri;
458
459 uri = g_file_get_uri (location);
460
461 if (eel_uri_is_desktop (uri))
462 {
463 directory = CAJA_DIRECTORY (g_object_new (CAJA_TYPE_DESKTOP_DIRECTORY, NULL));
464 }
465 else if (eel_uri_is_search (uri))
466 {
467 directory = CAJA_DIRECTORY (g_object_new (CAJA_TYPE_SEARCH_DIRECTORY, NULL));
468 }
469 else if (g_str_has_suffix (uri, CAJA_SAVED_SEARCH_EXTENSION))
470 {
471 directory = CAJA_DIRECTORY (caja_search_directory_new_from_saved_search (uri));
472 }
473 else
474 {
475 directory = CAJA_DIRECTORY (g_object_new (CAJA_TYPE_VFS_DIRECTORY, NULL));
476 }
477
478 set_directory_location (directory, location);
479
480 g_free (uri);
481
482 return directory;
483 }
484
485 gboolean
caja_directory_is_local(CajaDirectory * directory)486 caja_directory_is_local (CajaDirectory *directory)
487 {
488 g_return_val_if_fail (CAJA_IS_DIRECTORY (directory), FALSE);
489
490 if (directory->details->location == NULL)
491 {
492 return TRUE;
493 }
494
495 return caja_directory_is_in_trash (directory) ||
496 g_file_is_native (directory->details->location);
497 }
498
499 gboolean
caja_directory_is_in_trash(CajaDirectory * directory)500 caja_directory_is_in_trash (CajaDirectory *directory)
501 {
502 g_assert (CAJA_IS_DIRECTORY (directory));
503
504 if (directory->details->location == NULL)
505 {
506 return FALSE;
507 }
508
509 return g_file_has_uri_scheme (directory->details->location, "trash");
510 }
511
512 gboolean
caja_directory_are_all_files_seen(CajaDirectory * directory)513 caja_directory_are_all_files_seen (CajaDirectory *directory)
514 {
515 g_return_val_if_fail (CAJA_IS_DIRECTORY (directory), FALSE);
516
517 if (CAJA_DIRECTORY_GET_CLASS(directory)->are_all_files_seen == NULL)
518 {
519 return FALSE;
520 } else {
521 return CAJA_DIRECTORY_GET_CLASS(directory)->are_all_files_seen (directory);
522 }
523 }
524
525 static void
add_to_hash_table(CajaDirectory * directory,CajaFile * file,GList * node)526 add_to_hash_table (CajaDirectory *directory, CajaFile *file, GList *node)
527 {
528 const char *name;
529
530 name = file->details->name;
531
532 g_assert (node != NULL);
533 g_assert (g_hash_table_lookup (directory->details->file_hash,
534 name) == NULL);
535 g_hash_table_insert (directory->details->file_hash, (char *) name, node);
536 }
537
538 static GList *
extract_from_hash_table(CajaDirectory * directory,CajaFile * file)539 extract_from_hash_table (CajaDirectory *directory, CajaFile *file)
540 {
541 const char *name;
542 GList *node;
543
544 name = file->details->name;
545 if (name == NULL)
546 {
547 return NULL;
548 }
549
550 /* Find the list node in the hash table. */
551 node = g_hash_table_lookup (directory->details->file_hash, name);
552 g_hash_table_remove (directory->details->file_hash, name);
553
554 return node;
555 }
556
557 void
caja_directory_add_file(CajaDirectory * directory,CajaFile * file)558 caja_directory_add_file (CajaDirectory *directory, CajaFile *file)
559 {
560 GList *node;
561 gboolean add_to_work_queue;
562
563 g_assert (CAJA_IS_DIRECTORY (directory));
564 g_assert (CAJA_IS_FILE (file));
565 g_assert (file->details->name != NULL);
566
567 /* Add to list. */
568 node = g_list_prepend (directory->details->file_list, file);
569 directory->details->file_list = node;
570
571 /* Add to hash table. */
572 add_to_hash_table (directory, file, node);
573
574 directory->details->confirmed_file_count++;
575
576 add_to_work_queue = FALSE;
577 if (caja_directory_is_file_list_monitored (directory))
578 {
579 /* Ref if we are monitoring, since monitoring owns the file list. */
580 caja_file_ref (file);
581 add_to_work_queue = TRUE;
582 }
583 else if (caja_directory_has_active_request_for_file (directory, file))
584 {
585 /* We're waiting for the file in a call_when_ready. Make sure
586 we add the file to the work queue so that said waiter won't
587 wait forever for e.g. all files in the directory to be done */
588 add_to_work_queue = TRUE;
589 }
590
591 if (add_to_work_queue)
592 {
593 caja_directory_add_file_to_work_queue (directory, file);
594 }
595 }
596
597 void
caja_directory_remove_file(CajaDirectory * directory,CajaFile * file)598 caja_directory_remove_file (CajaDirectory *directory, CajaFile *file)
599 {
600 GList *node;
601
602 g_assert (CAJA_IS_DIRECTORY (directory));
603 g_assert (CAJA_IS_FILE (file));
604 g_assert (file->details->name != NULL);
605
606 /* Find the list node in the hash table. */
607 node = extract_from_hash_table (directory, file);
608 g_assert (node != NULL);
609 g_assert (node->data == file);
610
611 /* Remove the item from the list. */
612 directory->details->file_list = g_list_remove_link
613 (directory->details->file_list, node);
614 g_list_free_1 (node);
615
616 caja_directory_remove_file_from_work_queue (directory, file);
617
618 if (!file->details->unconfirmed)
619 {
620 directory->details->confirmed_file_count--;
621 }
622
623 /* Unref if we are monitoring. */
624 if (caja_directory_is_file_list_monitored (directory))
625 {
626 caja_file_unref (file);
627 }
628 }
629
630 GList *
caja_directory_begin_file_name_change(CajaDirectory * directory,CajaFile * file)631 caja_directory_begin_file_name_change (CajaDirectory *directory,
632 CajaFile *file)
633 {
634 /* Find the list node in the hash table. */
635 return extract_from_hash_table (directory, file);
636 }
637
638 void
caja_directory_end_file_name_change(CajaDirectory * directory,CajaFile * file,GList * node)639 caja_directory_end_file_name_change (CajaDirectory *directory,
640 CajaFile *file,
641 GList *node)
642 {
643 /* Add the list node to the hash table. */
644 if (node != NULL)
645 {
646 add_to_hash_table (directory, file, node);
647 }
648 }
649
650 CajaFile *
caja_directory_find_file_by_name(CajaDirectory * directory,const char * name)651 caja_directory_find_file_by_name (CajaDirectory *directory,
652 const char *name)
653 {
654 GList *node;
655
656 g_return_val_if_fail (CAJA_IS_DIRECTORY (directory), NULL);
657 g_return_val_if_fail (name != NULL, NULL);
658
659 node = g_hash_table_lookup (directory->details->file_hash,
660 name);
661 return node == NULL ? NULL : CAJA_FILE (node->data);
662 }
663
664 void
caja_directory_emit_files_added(CajaDirectory * directory,GList * added_files)665 caja_directory_emit_files_added (CajaDirectory *directory,
666 GList *added_files)
667 {
668 if (added_files != NULL)
669 {
670 g_signal_emit (directory,
671 signals[FILES_ADDED], 0,
672 added_files);
673 }
674 }
675
676 void
caja_directory_emit_files_changed(CajaDirectory * directory,GList * changed_files)677 caja_directory_emit_files_changed (CajaDirectory *directory,
678 GList *changed_files)
679 {
680 if (changed_files != NULL)
681 {
682 g_signal_emit (directory,
683 signals[FILES_CHANGED], 0,
684 changed_files);
685 }
686 }
687
688 void
caja_directory_emit_change_signals(CajaDirectory * directory,GList * changed_files)689 caja_directory_emit_change_signals (CajaDirectory *directory,
690 GList *changed_files)
691 {
692 GList *p;
693
694 for (p = changed_files; p != NULL; p = p->next)
695 {
696 caja_file_emit_changed (p->data);
697 }
698 caja_directory_emit_files_changed (directory, changed_files);
699 }
700
701 void
caja_directory_emit_done_loading(CajaDirectory * directory)702 caja_directory_emit_done_loading (CajaDirectory *directory)
703 {
704 g_signal_emit (directory,
705 signals[DONE_LOADING], 0);
706 }
707
708 void
caja_directory_emit_load_error(CajaDirectory * directory,GError * error)709 caja_directory_emit_load_error (CajaDirectory *directory,
710 GError *error)
711 {
712 g_signal_emit (directory,
713 signals[LOAD_ERROR], 0,
714 error);
715 }
716
717 /* Return a directory object for this one's parent. */
718 static CajaDirectory *
get_parent_directory(GFile * location)719 get_parent_directory (GFile *location)
720 {
721 GFile *parent;
722
723 parent = g_file_get_parent (location);
724 if (parent)
725 {
726 CajaDirectory *directory;
727
728 directory = caja_directory_get_internal (parent, TRUE);
729 g_object_unref (parent);
730 return directory;
731 }
732 return NULL;
733 }
734
735 /* If a directory object exists for this one's parent, then
736 * return it, otherwise return NULL.
737 */
738 static CajaDirectory *
get_parent_directory_if_exists(GFile * location)739 get_parent_directory_if_exists (GFile *location)
740 {
741 GFile *parent;
742
743 parent = g_file_get_parent (location);
744 if (parent)
745 {
746 CajaDirectory *directory;
747
748 directory = caja_directory_get_internal (parent, FALSE);
749 g_object_unref (parent);
750 return directory;
751 }
752 return NULL;
753 }
754
755 static void
hash_table_list_prepend(GHashTable * table,gconstpointer key,gpointer data)756 hash_table_list_prepend (GHashTable *table, gconstpointer key, gpointer data)
757 {
758 GList *list;
759
760 list = g_hash_table_lookup (table, key);
761 list = g_list_prepend (list, data);
762 g_hash_table_insert (table, (gpointer) key, list);
763 }
764
765 static void
call_files_added_free_list(gpointer key,gpointer value,gpointer user_data)766 call_files_added_free_list (gpointer key, gpointer value, gpointer user_data)
767 {
768 g_assert (CAJA_IS_DIRECTORY (key));
769 g_assert (value != NULL);
770 g_assert (user_data == NULL);
771
772 g_signal_emit (key,
773 signals[FILES_ADDED], 0,
774 value);
775 g_list_free (value);
776 }
777
778 static void
call_files_changed_common(CajaDirectory * directory,GList * file_list)779 call_files_changed_common (CajaDirectory *directory, GList *file_list)
780 {
781 GList *node;
782 CajaFile *file = NULL;
783
784 for (node = file_list; node != NULL; node = node->next)
785 {
786 file = node->data;
787 if (file->details->directory == directory)
788 {
789 caja_directory_add_file_to_work_queue (directory,
790 file);
791 }
792 }
793 caja_directory_async_state_changed (directory);
794 caja_directory_emit_change_signals (directory, file_list);
795 }
796
797 static void
call_files_changed_free_list(gpointer key,gpointer value,gpointer user_data)798 call_files_changed_free_list (gpointer key, gpointer value, gpointer user_data)
799 {
800 g_assert (value != NULL);
801 g_assert (user_data == NULL);
802
803 call_files_changed_common (CAJA_DIRECTORY (key), value);
804 g_list_free (value);
805 }
806
807 static void
call_files_changed_unref_free_list(gpointer key,gpointer value,gpointer user_data)808 call_files_changed_unref_free_list (gpointer key, gpointer value, gpointer user_data)
809 {
810 g_assert (value != NULL);
811 g_assert (user_data == NULL);
812
813 call_files_changed_common (CAJA_DIRECTORY (key), value);
814 caja_file_list_free (value);
815 }
816
817 static void
call_get_file_info_free_list(gpointer key,gpointer value,gpointer user_data)818 call_get_file_info_free_list (gpointer key, gpointer value, gpointer user_data)
819 {
820 CajaDirectory *directory;
821 GList *files;
822
823 g_assert (CAJA_IS_DIRECTORY (key));
824 g_assert (value != NULL);
825 g_assert (user_data == NULL);
826
827 directory = key;
828 files = value;
829
830 caja_directory_get_info_for_new_files (directory, files);
831 g_list_free_full (files, g_object_unref);
832 }
833
834 static void
invalidate_count_and_unref(gpointer key,gpointer value,gpointer user_data)835 invalidate_count_and_unref (gpointer key, gpointer value, gpointer user_data)
836 {
837 g_assert (CAJA_IS_DIRECTORY (key));
838 g_assert (value == key);
839 g_assert (user_data == NULL);
840
841 caja_directory_invalidate_count_and_mime_list (key);
842 caja_directory_unref (key);
843 }
844
845 static void
collect_parent_directories(GHashTable * hash_table,CajaDirectory * directory)846 collect_parent_directories (GHashTable *hash_table, CajaDirectory *directory)
847 {
848 g_assert (hash_table != NULL);
849 g_assert (CAJA_IS_DIRECTORY (directory));
850
851 if (g_hash_table_lookup (hash_table, directory) == NULL)
852 {
853 caja_directory_ref (directory);
854 g_hash_table_insert (hash_table, directory, directory);
855 }
856 }
857
858 void
caja_directory_notify_files_added(GList * files)859 caja_directory_notify_files_added (GList *files)
860 {
861 GHashTable *added_lists;
862 GList *p;
863 GHashTable *parent_directories;
864 CajaFile *file;
865 GFile *parent;
866 CajaDirectory *directory = NULL;
867 GFile *location = NULL;
868
869 /* Make a list of added files in each directory. */
870 added_lists = g_hash_table_new (NULL, NULL);
871
872 /* Make a list of parent directories that will need their counts updated. */
873 parent_directories = g_hash_table_new (NULL, NULL);
874
875 for (p = files; p != NULL; p = p->next)
876 {
877 location = p->data;
878
879 /* See if the directory is already known. */
880 directory = get_parent_directory_if_exists (location);
881 if (directory == NULL)
882 {
883 /* In case the directory is not being
884 * monitored, but the corresponding file is,
885 * we must invalidate it's item count.
886 */
887
888
889 file = NULL;
890 parent = g_file_get_parent (location);
891 if (parent)
892 {
893 file = caja_file_get_existing (parent);
894 g_object_unref (parent);
895 }
896
897 if (file != NULL)
898 {
899 caja_file_invalidate_count_and_mime_list (file);
900 caja_file_unref (file);
901 }
902
903 continue;
904 }
905
906 collect_parent_directories (parent_directories, directory);
907
908 /* If no one is monitoring files in the directory, nothing to do. */
909 if (!caja_directory_is_file_list_monitored (directory))
910 {
911 caja_directory_unref (directory);
912 continue;
913 }
914
915 file = caja_file_get_existing (location);
916 /* We check is_added here, because the file could have been added
917 * to the directory by a caja_file_get() but not gotten
918 * files_added emitted
919 */
920 if (file && file->details->is_added)
921 {
922 /* A file already exists, it was probably renamed.
923 * If it was renamed this could be ignored, but
924 * queue a change just in case */
925 caja_file_changed (file);
926 }
927 else
928 {
929 hash_table_list_prepend (added_lists,
930 directory,
931 g_object_ref (location));
932 }
933 caja_file_unref (file);
934 caja_directory_unref (directory);
935 }
936
937 /* Now get file info for the new files. This creates CajaFile
938 * objects for the new files, and sends out a files_added signal.
939 */
940 g_hash_table_foreach (added_lists, call_get_file_info_free_list, NULL);
941 g_hash_table_destroy (added_lists);
942
943 /* Invalidate count for each parent directory. */
944 g_hash_table_foreach (parent_directories, invalidate_count_and_unref, NULL);
945 g_hash_table_destroy (parent_directories);
946 }
947
948 void
caja_directory_notify_files_changed(GList * files)949 caja_directory_notify_files_changed (GList *files)
950 {
951 GHashTable *changed_lists;
952 GList *node;
953 GFile *location = NULL;
954 CajaFile *file = NULL;
955
956 /* Make a list of changed files in each directory. */
957 changed_lists = g_hash_table_new (NULL, NULL);
958
959 /* Go through all the notifications. */
960 for (node = files; node != NULL; node = node->next)
961 {
962 location = node->data;
963
964 /* Find the file. */
965 file = caja_file_get_existing (location);
966 if (file != NULL)
967 {
968 /* Tell it to re-get info now, and later emit
969 * a changed signal.
970 */
971 file->details->file_info_is_up_to_date = FALSE;
972 file->details->top_left_text_is_up_to_date = FALSE;
973 file->details->link_info_is_up_to_date = FALSE;
974 caja_file_invalidate_extension_info_internal (file);
975
976 hash_table_list_prepend (changed_lists,
977 file->details->directory,
978 file);
979 }
980 }
981 /* Now send out the changed signals. */
982 g_hash_table_foreach (changed_lists, call_files_changed_unref_free_list, NULL);
983 g_hash_table_destroy (changed_lists);
984 }
985
986 void
caja_directory_notify_files_removed(GList * files)987 caja_directory_notify_files_removed (GList *files)
988 {
989 GHashTable *changed_lists;
990 GList *p;
991 GHashTable *parent_directories;
992 CajaDirectory *directory = NULL;
993 CajaFile *file = NULL;
994 GFile *location = NULL;
995
996 /* Make a list of changed files in each directory. */
997 changed_lists = g_hash_table_new (NULL, NULL);
998
999 /* Make a list of parent directories that will need their counts updated. */
1000 parent_directories = g_hash_table_new (NULL, NULL);
1001
1002 /* Go through all the notifications. */
1003 for (p = files; p != NULL; p = p->next)
1004 {
1005 location = p->data;
1006
1007 /* Update file count for parent directory if anyone might care. */
1008 directory = get_parent_directory_if_exists (location);
1009 if (directory != NULL)
1010 {
1011 collect_parent_directories (parent_directories, directory);
1012 caja_directory_unref (directory);
1013 }
1014
1015 /* Find the file. */
1016 file = caja_file_get_existing (location);
1017 if (file != NULL && !caja_file_rename_in_progress (file))
1018 {
1019 /* Mark it gone and prepare to send the changed signal. */
1020 caja_file_mark_gone (file);
1021 hash_table_list_prepend (changed_lists,
1022 file->details->directory,
1023 caja_file_ref (file));
1024 }
1025 caja_file_unref (file);
1026 }
1027 /* Now send out the changed signals. */
1028 g_hash_table_foreach (changed_lists, call_files_changed_unref_free_list, NULL);
1029 g_hash_table_destroy (changed_lists);
1030
1031 /* Invalidate count for each parent directory. */
1032 g_hash_table_foreach (parent_directories, invalidate_count_and_unref, NULL);
1033 g_hash_table_destroy (parent_directories);
1034 }
1035
1036 static void
set_directory_location(CajaDirectory * directory,GFile * location)1037 set_directory_location (CajaDirectory *directory,
1038 GFile *location)
1039 {
1040 if (directory->details->location)
1041 {
1042 g_object_unref (directory->details->location);
1043 }
1044 directory->details->location = g_object_ref (location);
1045
1046 }
1047
1048 static void
change_directory_location(CajaDirectory * directory,GFile * new_location)1049 change_directory_location (CajaDirectory *directory,
1050 GFile *new_location)
1051 {
1052 /* I believe it's impossible for a self-owned file/directory
1053 * to be moved. But if that did somehow happen, this function
1054 * wouldn't do enough to handle it.
1055 */
1056 g_assert (directory->details->as_file == NULL);
1057
1058 g_hash_table_remove (directories,
1059 directory->details->location);
1060
1061 set_directory_location (directory, new_location);
1062
1063 g_hash_table_insert (directories,
1064 directory->details->location,
1065 directory);
1066 }
1067
1068 typedef struct
1069 {
1070 GFile *container;
1071 GList *directories;
1072 } CollectData;
1073
1074 static void
collect_directories_by_container(gpointer key,gpointer value,gpointer callback_data)1075 collect_directories_by_container (gpointer key, gpointer value, gpointer callback_data)
1076 {
1077 CajaDirectory *directory;
1078 CollectData *collect_data;
1079 GFile *location;
1080
1081 location = (GFile *) key;
1082 directory = CAJA_DIRECTORY (value);
1083 collect_data = (CollectData *) callback_data;
1084
1085 if (g_file_has_prefix (location, collect_data->container) ||
1086 g_file_equal (collect_data->container, location))
1087 {
1088 caja_directory_ref (directory);
1089 collect_data->directories =
1090 g_list_prepend (collect_data->directories,
1091 directory);
1092 }
1093 }
1094
1095 static GList *
caja_directory_moved_internal(GFile * old_location,GFile * new_location)1096 caja_directory_moved_internal (GFile *old_location,
1097 GFile *new_location)
1098 {
1099 CollectData collection;
1100 GList *node, *affected_files;
1101 char *relative_path;
1102 CajaDirectory *directory = NULL;
1103 GFile *new_directory_location = NULL;
1104
1105 collection.container = old_location;
1106 collection.directories = NULL;
1107
1108 g_hash_table_foreach (directories,
1109 collect_directories_by_container,
1110 &collection);
1111
1112 affected_files = NULL;
1113
1114 for (node = collection.directories; node != NULL; node = node->next)
1115 {
1116 directory = CAJA_DIRECTORY (node->data);
1117 new_directory_location = NULL;
1118
1119 if (g_file_equal (directory->details->location, old_location))
1120 {
1121 new_directory_location = g_object_ref (new_location);
1122 }
1123 else
1124 {
1125 relative_path = g_file_get_relative_path (old_location,
1126 directory->details->location);
1127 if (relative_path != NULL)
1128 {
1129 new_directory_location = g_file_resolve_relative_path (new_location, relative_path);
1130 g_free (relative_path);
1131
1132 }
1133 }
1134
1135 if (new_directory_location)
1136 {
1137 change_directory_location (directory, new_directory_location);
1138 g_object_unref (new_directory_location);
1139
1140 /* Collect affected files. */
1141 if (directory->details->as_file != NULL)
1142 {
1143 affected_files = g_list_prepend
1144 (affected_files,
1145 caja_file_ref (directory->details->as_file));
1146 }
1147 affected_files = g_list_concat
1148 (affected_files,
1149 caja_file_list_copy (directory->details->file_list));
1150 }
1151
1152 caja_directory_unref (directory);
1153 }
1154
1155 g_list_free (collection.directories);
1156
1157 return affected_files;
1158 }
1159
1160 void
caja_directory_moved(const char * old_uri,const char * new_uri)1161 caja_directory_moved (const char *old_uri,
1162 const char *new_uri)
1163 {
1164 GList *list, *node;
1165 GHashTable *hash;
1166 GFile *old_location;
1167 GFile *new_location;
1168 CajaFile *file = NULL;
1169
1170 hash = g_hash_table_new (NULL, NULL);
1171
1172 old_location = g_file_new_for_uri (old_uri);
1173 new_location = g_file_new_for_uri (new_uri);
1174
1175 list = caja_directory_moved_internal (old_location, new_location);
1176 for (node = list; node != NULL; node = node->next)
1177 {
1178 file = CAJA_FILE (node->data);
1179 hash_table_list_prepend (hash,
1180 file->details->directory,
1181 caja_file_ref (file));
1182 }
1183 caja_file_list_free (list);
1184
1185 g_object_unref (old_location);
1186 g_object_unref (new_location);
1187
1188 g_hash_table_foreach (hash, call_files_changed_unref_free_list, NULL);
1189 g_hash_table_destroy (hash);
1190 }
1191
1192 void
caja_directory_notify_files_moved(GList * file_pairs)1193 caja_directory_notify_files_moved (GList *file_pairs)
1194 {
1195 GList *p, *affected_files, *node;
1196 GFilePair *pair;
1197 CajaFile *file;
1198 CajaDirectory *old_directory, *new_directory;
1199 GHashTable *parent_directories;
1200 GList *new_files_list, *unref_list;
1201 GHashTable *added_lists, *changed_lists;
1202 char *name;
1203 CajaFileAttributes cancel_attributes;
1204 GFile *to_location = NULL;
1205 GFile *from_location = NULL;
1206
1207 /* Make a list of added and changed files in each directory. */
1208 new_files_list = NULL;
1209 added_lists = g_hash_table_new (NULL, NULL);
1210 changed_lists = g_hash_table_new (NULL, NULL);
1211 unref_list = NULL;
1212
1213 /* Make a list of parent directories that will need their counts updated. */
1214 parent_directories = g_hash_table_new (NULL, NULL);
1215
1216 cancel_attributes = caja_file_get_all_attributes ();
1217
1218 for (p = file_pairs; p != NULL; p = p->next)
1219 {
1220 pair = p->data;
1221 from_location = pair->from;
1222 to_location = pair->to;
1223
1224 /* Handle overwriting a file. */
1225 file = caja_file_get_existing (to_location);
1226 if (file != NULL)
1227 {
1228 /* Mark it gone and prepare to send the changed signal. */
1229 caja_file_mark_gone (file);
1230 new_directory = file->details->directory;
1231 hash_table_list_prepend (changed_lists,
1232 new_directory,
1233 file);
1234 collect_parent_directories (parent_directories,
1235 new_directory);
1236 }
1237
1238 /* Update any directory objects that are affected. */
1239 affected_files = caja_directory_moved_internal (from_location,
1240 to_location);
1241 for (node = affected_files; node != NULL; node = node->next)
1242 {
1243 file = CAJA_FILE (node->data);
1244 hash_table_list_prepend (changed_lists,
1245 file->details->directory,
1246 file);
1247 }
1248 unref_list = g_list_concat (unref_list, affected_files);
1249
1250 /* Move an existing file. */
1251 file = caja_file_get_existing (from_location);
1252 if (file == NULL)
1253 {
1254 /* Handle this as if it was a new file. */
1255 new_files_list = g_list_prepend (new_files_list,
1256 to_location);
1257 }
1258 else
1259 {
1260 /* Handle notification in the old directory. */
1261 old_directory = file->details->directory;
1262 collect_parent_directories (parent_directories, old_directory);
1263
1264 /* Cancel loading of attributes in the old directory */
1265 caja_directory_cancel_loading_file_attributes
1266 (old_directory, file, cancel_attributes);
1267
1268 /* Locate the new directory. */
1269 new_directory = get_parent_directory (to_location);
1270 collect_parent_directories (parent_directories, new_directory);
1271 /* We can unref now -- new_directory is in the
1272 * parent directories list so it will be
1273 * around until the end of this function
1274 * anyway.
1275 */
1276 caja_directory_unref (new_directory);
1277
1278 /* Update the file's name and directory. */
1279 name = g_file_get_basename (to_location);
1280 caja_file_update_name_and_directory
1281 (file, name, new_directory);
1282 g_free (name);
1283
1284 /* Update file attributes */
1285 caja_file_invalidate_attributes (file, CAJA_FILE_ATTRIBUTE_INFO);
1286
1287 hash_table_list_prepend (changed_lists,
1288 old_directory,
1289 file);
1290 if (old_directory != new_directory)
1291 {
1292 hash_table_list_prepend (added_lists,
1293 new_directory,
1294 file);
1295 }
1296
1297 /* Unref each file once to balance out caja_file_get_by_uri. */
1298 unref_list = g_list_prepend (unref_list, file);
1299 }
1300 }
1301
1302 /* Now send out the changed and added signals for existing file objects. */
1303 g_hash_table_foreach (changed_lists, call_files_changed_free_list, NULL);
1304 g_hash_table_destroy (changed_lists);
1305 g_hash_table_foreach (added_lists, call_files_added_free_list, NULL);
1306 g_hash_table_destroy (added_lists);
1307
1308 /* Let the file objects go. */
1309 caja_file_list_free (unref_list);
1310
1311 /* Invalidate count for each parent directory. */
1312 g_hash_table_foreach (parent_directories, invalidate_count_and_unref, NULL);
1313 g_hash_table_destroy (parent_directories);
1314
1315 /* Separate handling for brand new file objects. */
1316 caja_directory_notify_files_added (new_files_list);
1317 g_list_free (new_files_list);
1318 }
1319
1320 void
caja_directory_schedule_position_set(GList * position_setting_list)1321 caja_directory_schedule_position_set (GList *position_setting_list)
1322 {
1323 GList *p;
1324 char str[64];
1325 time_t now;
1326 const CajaFileChangesQueuePosition *item = NULL;
1327 CajaFile *file = NULL;
1328
1329 time (&now);
1330
1331 for (p = position_setting_list; p != NULL; p = p->next)
1332 {
1333 item = (CajaFileChangesQueuePosition *) p->data;
1334
1335 file = caja_file_get (item->location);
1336
1337 if (item->set)
1338 {
1339 g_snprintf (str, sizeof (str), "%d,%d", item->point.x, item->point.y);
1340 }
1341 else
1342 {
1343 str[0] = 0;
1344 }
1345 caja_file_set_metadata
1346 (file,
1347 CAJA_METADATA_KEY_ICON_POSITION,
1348 NULL,
1349 str);
1350
1351 if (item->set)
1352 {
1353 caja_file_set_time_metadata
1354 (file,
1355 CAJA_METADATA_KEY_ICON_POSITION_TIMESTAMP,
1356 now);
1357 }
1358 else
1359 {
1360 caja_file_set_time_metadata
1361 (file,
1362 CAJA_METADATA_KEY_ICON_POSITION_TIMESTAMP,
1363 UNDEFINED_TIME);
1364 }
1365
1366 if (item->set)
1367 {
1368 g_snprintf (str, sizeof (str), "%d", item->screen);
1369 }
1370 else
1371 {
1372 str[0] = 0;
1373 }
1374 caja_file_set_metadata
1375 (file,
1376 CAJA_METADATA_KEY_SCREEN,
1377 NULL,
1378 str);
1379
1380 caja_file_unref (file);
1381 }
1382 }
1383
1384 gboolean
caja_directory_contains_file(CajaDirectory * directory,CajaFile * file)1385 caja_directory_contains_file (CajaDirectory *directory,
1386 CajaFile *file)
1387 {
1388 g_return_val_if_fail (CAJA_IS_DIRECTORY (directory), FALSE);
1389 g_return_val_if_fail (CAJA_IS_FILE (file), FALSE);
1390
1391 if (caja_file_is_gone (file))
1392 {
1393 return FALSE;
1394 }
1395
1396 if (CAJA_DIRECTORY_GET_CLASS(directory)->contains_file == NULL)
1397 return FALSE;
1398 else
1399 return CAJA_DIRECTORY_GET_CLASS(directory)->contains_file (directory, file);
1400 }
1401
1402 void
caja_directory_call_when_ready(CajaDirectory * directory,CajaFileAttributes file_attributes,gboolean wait_for_all_files,CajaDirectoryCallback callback,gpointer callback_data)1403 caja_directory_call_when_ready (CajaDirectory *directory,
1404 CajaFileAttributes file_attributes,
1405 gboolean wait_for_all_files,
1406 CajaDirectoryCallback callback,
1407 gpointer callback_data)
1408 {
1409 g_return_if_fail (CAJA_IS_DIRECTORY (directory));
1410 g_return_if_fail (callback != NULL);
1411
1412 if (CAJA_DIRECTORY_GET_CLASS(directory)->call_when_ready != NULL)
1413 {
1414 CAJA_DIRECTORY_GET_CLASS(directory)->call_when_ready (directory,
1415 file_attributes,
1416 wait_for_all_files,
1417 callback,
1418 callback_data);
1419 }
1420 }
1421
1422 void
caja_directory_cancel_callback(CajaDirectory * directory,CajaDirectoryCallback callback,gpointer callback_data)1423 caja_directory_cancel_callback (CajaDirectory *directory,
1424 CajaDirectoryCallback callback,
1425 gpointer callback_data)
1426 {
1427 g_return_if_fail (CAJA_IS_DIRECTORY (directory));
1428 g_return_if_fail (callback != NULL);
1429
1430 if (CAJA_DIRECTORY_GET_CLASS(directory)->cancel_callback != NULL)
1431 {
1432 CAJA_DIRECTORY_GET_CLASS(directory)->cancel_callback (directory, callback, callback_data);
1433 }
1434 }
1435
1436 void
caja_directory_file_monitor_add(CajaDirectory * directory,gconstpointer client,gboolean monitor_hidden_files,CajaFileAttributes file_attributes,CajaDirectoryCallback callback,gpointer callback_data)1437 caja_directory_file_monitor_add (CajaDirectory *directory,
1438 gconstpointer client,
1439 gboolean monitor_hidden_files,
1440 CajaFileAttributes file_attributes,
1441 CajaDirectoryCallback callback,
1442 gpointer callback_data)
1443 {
1444 g_return_if_fail (CAJA_IS_DIRECTORY (directory));
1445 g_return_if_fail (client != NULL);
1446
1447 if (CAJA_DIRECTORY_GET_CLASS(directory)->file_monitor_add != NULL)
1448 {
1449 CAJA_DIRECTORY_GET_CLASS(directory)->file_monitor_add (directory,
1450 client,
1451 monitor_hidden_files,
1452 file_attributes,
1453 callback, callback_data);
1454 }
1455 }
1456
1457 void
caja_directory_file_monitor_remove(CajaDirectory * directory,gconstpointer client)1458 caja_directory_file_monitor_remove (CajaDirectory *directory,
1459 gconstpointer client)
1460 {
1461 g_return_if_fail (CAJA_IS_DIRECTORY (directory));
1462 g_return_if_fail (client != NULL);
1463
1464 if (CAJA_DIRECTORY_GET_CLASS(directory)->file_monitor_remove != NULL)
1465 {
1466 CAJA_DIRECTORY_GET_CLASS(directory)->file_monitor_remove (directory, client);
1467 }
1468 }
1469
1470 void
caja_directory_force_reload(CajaDirectory * directory)1471 caja_directory_force_reload (CajaDirectory *directory)
1472 {
1473 g_return_if_fail (CAJA_IS_DIRECTORY (directory));
1474
1475 if (CAJA_DIRECTORY_GET_CLASS(directory)->force_reload != NULL)
1476 {
1477 CAJA_DIRECTORY_GET_CLASS(directory)->force_reload (directory);
1478 }
1479 }
1480
1481 gboolean
caja_directory_is_not_empty(CajaDirectory * directory)1482 caja_directory_is_not_empty (CajaDirectory *directory)
1483 {
1484 g_return_val_if_fail (CAJA_IS_DIRECTORY (directory), FALSE);
1485
1486 if (CAJA_DIRECTORY_GET_CLASS(directory)->is_not_empty == NULL)
1487 {
1488 return FALSE;
1489 } else {
1490 return CAJA_DIRECTORY_GET_CLASS(directory)->is_not_empty (directory);
1491 }
1492 }
1493
1494 static gboolean
is_tentative(gpointer data,gpointer callback_data)1495 is_tentative (gpointer data, gpointer callback_data)
1496 {
1497 CajaFile *file;
1498
1499 g_assert (callback_data == NULL);
1500
1501 file = CAJA_FILE (data);
1502 /* Avoid returning files with !is_added, because these
1503 * will later be sent with the files_added signal, and a
1504 * user doing get_file_list + files_added monitoring will
1505 * then see the file twice */
1506 return !file->details->got_file_info || !file->details->is_added;
1507 }
1508
1509 GList *
caja_directory_get_file_list(CajaDirectory * directory)1510 caja_directory_get_file_list (CajaDirectory *directory)
1511 {
1512 if (CAJA_DIRECTORY_GET_CLASS(directory)->get_file_list == NULL)
1513 {
1514 return NULL;
1515 } else {
1516 return CAJA_DIRECTORY_GET_CLASS(directory)->get_file_list (directory);
1517 }
1518 }
1519
1520 static GList *
real_get_file_list(CajaDirectory * directory)1521 real_get_file_list (CajaDirectory *directory)
1522 {
1523 GList *tentative_files, *non_tentative_files;
1524
1525 tentative_files = eel_g_list_partition
1526 (g_list_copy (directory->details->file_list),
1527 is_tentative, NULL, &non_tentative_files);
1528 g_list_free (tentative_files);
1529
1530 caja_file_list_ref (non_tentative_files);
1531 return non_tentative_files;
1532 }
1533
1534 static gboolean
real_is_editable(CajaDirectory * directory)1535 real_is_editable (CajaDirectory *directory)
1536 {
1537 return TRUE;
1538 }
1539
1540 gboolean
caja_directory_is_editable(CajaDirectory * directory)1541 caja_directory_is_editable (CajaDirectory *directory)
1542 {
1543 if (CAJA_DIRECTORY_GET_CLASS(directory)->is_editable == NULL)
1544 {
1545 return FALSE;
1546 } else {
1547 return CAJA_DIRECTORY_GET_CLASS(directory)->is_editable (directory);
1548 }
1549 }
1550
1551 GList *
caja_directory_match_pattern(CajaDirectory * directory,const char * pattern)1552 caja_directory_match_pattern (CajaDirectory *directory, const char *pattern)
1553 {
1554 GList *files, *l, *ret;
1555 GPatternSpec *spec;
1556
1557
1558 ret = NULL;
1559 spec = g_pattern_spec_new (pattern);
1560
1561 files = caja_directory_get_file_list (directory);
1562 for (l = files; l; l = l->next)
1563 {
1564 CajaFile *file;
1565 char *name;
1566
1567 file = CAJA_FILE (l->data);
1568 name = caja_file_get_display_name (file);
1569
1570 if (g_pattern_match_string (spec, name))
1571 {
1572 ret = g_list_prepend(ret, caja_file_ref (file));
1573 }
1574
1575 g_free (name);
1576 }
1577
1578 g_pattern_spec_free (spec);
1579 caja_file_list_free (files);
1580
1581 return ret;
1582 }
1583
1584 /**
1585 * caja_directory_list_ref
1586 *
1587 * Ref all the directories in a list.
1588 * @list: GList of directories.
1589 **/
1590 GList *
caja_directory_list_ref(GList * list)1591 caja_directory_list_ref (GList *list)
1592 {
1593 g_list_foreach (list, (GFunc) caja_directory_ref, NULL);
1594 return list;
1595 }
1596
1597 /**
1598 * caja_directory_list_unref
1599 *
1600 * Unref all the directories in a list.
1601 * @list: GList of directories.
1602 **/
1603 void
caja_directory_list_unref(GList * list)1604 caja_directory_list_unref (GList *list)
1605 {
1606 g_list_foreach (list, (GFunc) caja_directory_unref, NULL);
1607 }
1608
1609 /**
1610 * caja_directory_list_free
1611 *
1612 * Free a list of directories after unrefing them.
1613 * @list: GList of directories.
1614 **/
1615 void
caja_directory_list_free(GList * list)1616 caja_directory_list_free (GList *list)
1617 {
1618 caja_directory_list_unref (list);
1619 g_list_free (list);
1620 }
1621
1622 /**
1623 * caja_directory_list_copy
1624 *
1625 * Copy the list of directories, making a new ref of each,
1626 * @list: GList of directories.
1627 **/
1628 GList *
caja_directory_list_copy(GList * list)1629 caja_directory_list_copy (GList *list)
1630 {
1631 return g_list_copy (caja_directory_list_ref (list));
1632 }
1633
1634 static int
compare_by_uri(CajaDirectory * a,CajaDirectory * b)1635 compare_by_uri (CajaDirectory *a, CajaDirectory *b)
1636 {
1637 char *uri_a, *uri_b;
1638 int res;
1639
1640 uri_a = g_file_get_uri (a->details->location);
1641 uri_b = g_file_get_uri (b->details->location);
1642
1643 res = strcmp (uri_a, uri_b);
1644
1645 g_free (uri_a);
1646 g_free (uri_b);
1647
1648 return res;
1649 }
1650
1651 static int
compare_by_uri_cover(gconstpointer a,gconstpointer b)1652 compare_by_uri_cover (gconstpointer a, gconstpointer b)
1653 {
1654 return compare_by_uri (CAJA_DIRECTORY (a), CAJA_DIRECTORY (b));
1655 }
1656
1657 /**
1658 * caja_directory_list_sort_by_uri
1659 *
1660 * Sort the list of directories by directory uri.
1661 * @list: GList of directories.
1662 **/
1663 GList *
caja_directory_list_sort_by_uri(GList * list)1664 caja_directory_list_sort_by_uri (GList *list)
1665 {
1666 return g_list_sort (list, compare_by_uri_cover);
1667 }
1668
1669 gboolean
caja_directory_is_desktop_directory(CajaDirectory * directory)1670 caja_directory_is_desktop_directory (CajaDirectory *directory)
1671 {
1672 if (directory->details->location == NULL)
1673 {
1674 return FALSE;
1675 }
1676
1677 return caja_is_desktop_directory (directory->details->location);
1678 }
1679
1680 #if !defined (CAJA_OMIT_SELF_CHECK)
1681
1682 #include <eel/eel-debug.h>
1683 #include "caja-file-attributes.h"
1684
1685 static int data_dummy;
1686 static gboolean got_files_flag;
1687
1688 static void
got_files_callback(CajaDirectory * directory,GList * files,gpointer callback_data)1689 got_files_callback (CajaDirectory *directory, GList *files, gpointer callback_data)
1690 {
1691 g_assert (CAJA_IS_DIRECTORY (directory));
1692 g_assert (g_list_length (files) > 10);
1693 g_assert (callback_data == &data_dummy);
1694
1695 got_files_flag = TRUE;
1696 }
1697
1698 /* Return the number of extant CajaDirectories */
1699 int
caja_directory_number_outstanding(void)1700 caja_directory_number_outstanding (void)
1701 {
1702 return directories ? g_hash_table_size (directories) : 0;
1703 }
1704
1705 void
caja_self_check_directory(void)1706 caja_self_check_directory (void)
1707 {
1708 CajaDirectory *directory;
1709 CajaFile *file;
1710
1711 directory = caja_directory_get_by_uri ("file:///etc");
1712 file = caja_file_get_by_uri ("file:///etc/passwd");
1713
1714 EEL_CHECK_INTEGER_RESULT (g_hash_table_size (directories), 1);
1715
1716 caja_directory_file_monitor_add
1717 (directory, &data_dummy,
1718 TRUE, 0, NULL, NULL);
1719
1720 /* FIXME: these need to be updated to the new metadata infrastructure
1721 * as make check doesn't pass.
1722 caja_file_set_metadata (file, "test", "default", "value");
1723 EEL_CHECK_STRING_RESULT (caja_file_get_metadata (file, "test", "default"), "value");
1724
1725 caja_file_set_boolean_metadata (file, "test_boolean", TRUE, TRUE);
1726 EEL_CHECK_BOOLEAN_RESULT (caja_file_get_boolean_metadata (file, "test_boolean", TRUE), TRUE);
1727 caja_file_set_boolean_metadata (file, "test_boolean", TRUE, FALSE);
1728 EEL_CHECK_BOOLEAN_RESULT (caja_file_get_boolean_metadata (file, "test_boolean", TRUE), FALSE);
1729 EEL_CHECK_BOOLEAN_RESULT (caja_file_get_boolean_metadata (NULL, "test_boolean", TRUE), TRUE);
1730
1731 caja_file_set_integer_metadata (file, "test_integer", 0, 17);
1732 EEL_CHECK_INTEGER_RESULT (caja_file_get_integer_metadata (file, "test_integer", 0), 17);
1733 caja_file_set_integer_metadata (file, "test_integer", 0, -1);
1734 EEL_CHECK_INTEGER_RESULT (caja_file_get_integer_metadata (file, "test_integer", 0), -1);
1735 caja_file_set_integer_metadata (file, "test_integer", 42, 42);
1736 EEL_CHECK_INTEGER_RESULT (caja_file_get_integer_metadata (file, "test_integer", 42), 42);
1737 EEL_CHECK_INTEGER_RESULT (caja_file_get_integer_metadata (NULL, "test_integer", 42), 42);
1738 EEL_CHECK_INTEGER_RESULT (caja_file_get_integer_metadata (file, "nonexistent_key", 42), 42);
1739 */
1740
1741 EEL_CHECK_BOOLEAN_RESULT (caja_directory_get_by_uri ("file:///etc") == directory, TRUE);
1742 caja_directory_unref (directory);
1743
1744 EEL_CHECK_BOOLEAN_RESULT (caja_directory_get_by_uri ("file:///etc/") == directory, TRUE);
1745 caja_directory_unref (directory);
1746
1747 EEL_CHECK_BOOLEAN_RESULT (caja_directory_get_by_uri ("file:///etc////") == directory, TRUE);
1748 caja_directory_unref (directory);
1749
1750 caja_file_unref (file);
1751
1752 caja_directory_file_monitor_remove (directory, &data_dummy);
1753
1754 caja_directory_unref (directory);
1755
1756 while (g_hash_table_size (directories) != 0)
1757 {
1758 gtk_main_iteration ();
1759 }
1760
1761 EEL_CHECK_INTEGER_RESULT (g_hash_table_size (directories), 0);
1762
1763 directory = caja_directory_get_by_uri ("file:///etc");
1764
1765 got_files_flag = FALSE;
1766
1767 caja_directory_call_when_ready (directory,
1768 CAJA_FILE_ATTRIBUTE_INFO |
1769 CAJA_FILE_ATTRIBUTE_DEEP_COUNTS,
1770 TRUE,
1771 got_files_callback, &data_dummy);
1772
1773 while (!got_files_flag)
1774 {
1775 gtk_main_iteration ();
1776 }
1777
1778 EEL_CHECK_BOOLEAN_RESULT (directory->details->file_list == NULL, TRUE);
1779
1780 EEL_CHECK_INTEGER_RESULT (g_hash_table_size (directories), 1);
1781
1782 file = caja_file_get_by_uri ("file:///etc/passwd");
1783
1784 /* EEL_CHECK_STRING_RESULT (caja_file_get_metadata (file, "test", "default"), "value"); */
1785
1786 caja_file_unref (file);
1787
1788 caja_directory_unref (directory);
1789
1790 EEL_CHECK_INTEGER_RESULT (g_hash_table_size (directories), 0);
1791 }
1792
1793 #endif /* !CAJA_OMIT_SELF_CHECK */
1794