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