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