summaryrefslogtreecommitdiff
path: root/libcaja-private/caja-directory.c
diff options
context:
space:
mode:
Diffstat (limited to 'libcaja-private/caja-directory.c')
-rw-r--r--libcaja-private/caja-directory.c2004
1 files changed, 2004 insertions, 0 deletions
diff --git a/libcaja-private/caja-directory.c b/libcaja-private/caja-directory.c
new file mode 100644
index 00000000..5c1aa80d
--- /dev/null
+++ b/libcaja-private/caja-directory.c
@@ -0,0 +1,2004 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*-
+
+ caja-directory.c: Caja directory model.
+
+ Copyright (C) 1999, 2000, 2001 Eazel, Inc.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public
+ License along with this program; if not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+ Author: Darin Adler <[email protected]>
+*/
+
+#include <config.h>
+#include "caja-directory-private.h"
+
+#include "caja-directory-notify.h"
+#include "caja-file-attributes.h"
+#include "caja-file-private.h"
+#include "caja-file-utilities.h"
+#include "caja-search-directory.h"
+#include "caja-global-preferences.h"
+#include "caja-lib-self-check-functions.h"
+#include "caja-marshal.h"
+#include "caja-metadata.h"
+#include "caja-desktop-directory.h"
+#include "caja-vfs-directory.h"
+#include <eel/eel-glib-extensions.h>
+#include <eel/eel-gtk-macros.h>
+#include <eel/eel-string.h>
+#include <gtk/gtk.h>
+
+enum
+{
+ FILES_ADDED,
+ FILES_CHANGED,
+ DONE_LOADING,
+ LOAD_ERROR,
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL];
+
+static GHashTable *directories;
+
+static void caja_directory_finalize (GObject *object);
+static void caja_directory_init (gpointer object,
+ gpointer klass);
+static void caja_directory_class_init (CajaDirectoryClass *klass);
+static CajaDirectory *caja_directory_new (GFile *location);
+static char * real_get_name_for_self_as_new_file (CajaDirectory *directory);
+static GList * real_get_file_list (CajaDirectory *directory);
+static gboolean real_is_editable (CajaDirectory *directory);
+static void set_directory_location (CajaDirectory *directory,
+ GFile *location);
+
+EEL_CLASS_BOILERPLATE (CajaDirectory,
+ caja_directory,
+ G_TYPE_OBJECT)
+
+static void
+caja_directory_class_init (CajaDirectoryClass *klass)
+{
+ GObjectClass *object_class;
+
+ object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = caja_directory_finalize;
+
+ signals[FILES_ADDED] =
+ g_signal_new ("files_added",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (CajaDirectoryClass, files_added),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__POINTER,
+ G_TYPE_NONE, 1, G_TYPE_POINTER);
+ signals[FILES_CHANGED] =
+ g_signal_new ("files_changed",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (CajaDirectoryClass, files_changed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__POINTER,
+ G_TYPE_NONE, 1, G_TYPE_POINTER);
+ signals[DONE_LOADING] =
+ g_signal_new ("done_loading",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (CajaDirectoryClass, done_loading),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+ signals[LOAD_ERROR] =
+ g_signal_new ("load_error",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (CajaDirectoryClass, load_error),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__POINTER,
+ G_TYPE_NONE, 1, G_TYPE_POINTER);
+
+ klass->get_name_for_self_as_new_file = real_get_name_for_self_as_new_file;
+ klass->get_file_list = real_get_file_list;
+ klass->is_editable = real_is_editable;
+
+ g_type_class_add_private (klass, sizeof (CajaDirectoryDetails));
+}
+
+static void
+caja_directory_init (gpointer object, gpointer klass)
+{
+ CajaDirectory *directory;
+
+ directory = CAJA_DIRECTORY(object);
+
+ directory->details = G_TYPE_INSTANCE_GET_PRIVATE ((directory), CAJA_TYPE_DIRECTORY, CajaDirectoryDetails);
+ directory->details->file_hash = g_hash_table_new (g_str_hash, g_str_equal);
+ directory->details->high_priority_queue = caja_file_queue_new ();
+ directory->details->low_priority_queue = caja_file_queue_new ();
+ directory->details->extension_queue = caja_file_queue_new ();
+ directory->details->free_space = (guint64)-1;
+}
+
+CajaDirectory *
+caja_directory_ref (CajaDirectory *directory)
+{
+ if (directory == NULL)
+ {
+ return directory;
+ }
+
+ g_return_val_if_fail (CAJA_IS_DIRECTORY (directory), NULL);
+
+ g_object_ref (directory);
+ return directory;
+}
+
+void
+caja_directory_unref (CajaDirectory *directory)
+{
+ if (directory == NULL)
+ {
+ return;
+ }
+
+ g_return_if_fail (CAJA_IS_DIRECTORY (directory));
+
+ g_object_unref (directory);
+}
+
+static void
+caja_directory_finalize (GObject *object)
+{
+ CajaDirectory *directory;
+
+ directory = CAJA_DIRECTORY (object);
+
+ g_hash_table_remove (directories, directory->details->location);
+
+ caja_directory_cancel (directory);
+ g_assert (directory->details->count_in_progress == NULL);
+ g_assert (directory->details->top_left_read_state == NULL);
+
+ if (directory->details->monitor_list != NULL)
+ {
+ g_warning ("destroying a CajaDirectory while it's being monitored");
+ eel_g_list_free_deep (directory->details->monitor_list);
+ }
+
+ if (directory->details->monitor != NULL)
+ {
+ caja_monitor_cancel (directory->details->monitor);
+ }
+
+ if (directory->details->dequeue_pending_idle_id != 0)
+ {
+ g_source_remove (directory->details->dequeue_pending_idle_id);
+ }
+
+ if (directory->details->call_ready_idle_id != 0)
+ {
+ g_source_remove (directory->details->call_ready_idle_id);
+ }
+
+ if (directory->details->location)
+ {
+ g_object_unref (directory->details->location);
+ }
+
+ g_assert (directory->details->file_list == NULL);
+ g_hash_table_destroy (directory->details->file_hash);
+
+ if (directory->details->hidden_file_hash)
+ {
+ g_hash_table_destroy (directory->details->hidden_file_hash);
+ }
+
+ caja_file_queue_destroy (directory->details->high_priority_queue);
+ caja_file_queue_destroy (directory->details->low_priority_queue);
+ caja_file_queue_destroy (directory->details->extension_queue);
+ g_assert (directory->details->directory_load_in_progress == NULL);
+ g_assert (directory->details->count_in_progress == NULL);
+ g_assert (directory->details->dequeue_pending_idle_id == 0);
+ eel_g_object_list_free (directory->details->pending_file_info);
+
+ EEL_CALL_PARENT (G_OBJECT_CLASS, finalize, (object));
+}
+
+static void
+invalidate_one_count (gpointer key, gpointer value, gpointer user_data)
+{
+ CajaDirectory *directory;
+
+ g_assert (key != NULL);
+ g_assert (CAJA_IS_DIRECTORY (value));
+ g_assert (user_data == NULL);
+
+ directory = CAJA_DIRECTORY (value);
+
+ caja_directory_invalidate_count_and_mime_list (directory);
+}
+
+static void
+filtering_changed_callback (gpointer callback_data)
+{
+ g_assert (callback_data == NULL);
+
+ /* Preference about which items to show has changed, so we
+ * can't trust any of our precomputed directory counts.
+ */
+ g_hash_table_foreach (directories, invalidate_one_count, NULL);
+}
+
+void
+emit_change_signals_for_all_files (CajaDirectory *directory)
+{
+ GList *files;
+
+ files = g_list_copy (directory->details->file_list);
+ if (directory->details->as_file != NULL)
+ {
+ files = g_list_prepend (files, directory->details->as_file);
+ }
+
+ caja_file_list_ref (files);
+ caja_directory_emit_change_signals (directory, files);
+
+ caja_file_list_free (files);
+}
+
+static void
+collect_all_directories (gpointer key, gpointer value, gpointer callback_data)
+{
+ CajaDirectory *directory;
+ GList **dirs;
+ GFile *location;
+
+ location = (GFile *) key;
+ directory = CAJA_DIRECTORY (value);
+ dirs = callback_data;
+
+ *dirs = g_list_prepend (*dirs, caja_directory_ref (directory));
+}
+
+void
+emit_change_signals_for_all_files_in_all_directories (void)
+{
+ GList *dirs, *l;
+ CajaDirectory *directory;
+
+ dirs = NULL;
+ g_hash_table_foreach (directories,
+ collect_all_directories,
+ &dirs);
+
+ for (l = dirs; l != NULL; l = l->next)
+ {
+ directory = CAJA_DIRECTORY (l->data);
+ emit_change_signals_for_all_files (directory);
+ caja_directory_unref (directory);
+ }
+
+ g_list_free (dirs);
+}
+
+static void
+async_state_changed_one (gpointer key, gpointer value, gpointer user_data)
+{
+ CajaDirectory *directory;
+
+ g_assert (key != NULL);
+ g_assert (CAJA_IS_DIRECTORY (value));
+ g_assert (user_data == NULL);
+
+ directory = CAJA_DIRECTORY (value);
+
+ caja_directory_async_state_changed (directory);
+ emit_change_signals_for_all_files (directory);
+}
+
+static void
+async_data_preference_changed_callback (gpointer callback_data)
+{
+ g_assert (callback_data == NULL);
+
+ /* Preference involving fetched async data has changed, so
+ * we have to kick off refetching all async data, and tell
+ * each file that it (might have) changed.
+ */
+ g_hash_table_foreach (directories, async_state_changed_one, NULL);
+}
+
+static void
+add_preferences_callbacks (void)
+{
+ caja_global_preferences_init ();
+
+ eel_preferences_add_callback (CAJA_PREFERENCES_SHOW_HIDDEN_FILES,
+ filtering_changed_callback,
+ NULL);
+ eel_preferences_add_callback (CAJA_PREFERENCES_SHOW_BACKUP_FILES,
+ filtering_changed_callback,
+ NULL);
+ eel_preferences_add_callback (CAJA_PREFERENCES_SHOW_TEXT_IN_ICONS,
+ async_data_preference_changed_callback,
+ NULL);
+ eel_preferences_add_callback (CAJA_PREFERENCES_SHOW_DIRECTORY_ITEM_COUNTS,
+ async_data_preference_changed_callback,
+ NULL);
+ eel_preferences_add_callback (CAJA_PREFERENCES_DATE_FORMAT,
+ async_data_preference_changed_callback,
+ NULL);
+}
+
+/**
+ * caja_directory_get_by_uri:
+ * @uri: URI of directory to get.
+ *
+ * Get a directory given a uri.
+ * Creates the appropriate subclass given the uri mappings.
+ * Returns a referenced object, not a floating one. Unref when finished.
+ * If two windows are viewing the same uri, the directory object is shared.
+ */
+CajaDirectory *
+caja_directory_get_internal (GFile *location, gboolean create)
+{
+ CajaDirectory *directory;
+
+ /* Create the hash table first time through. */
+ if (directories == NULL)
+ {
+ directories = eel_g_hash_table_new_free_at_exit
+ (g_file_hash, (GCompareFunc)g_file_equal, "caja-directory.c: directories");
+
+ add_preferences_callbacks ();
+ }
+
+ /* If the object is already in the hash table, look it up. */
+
+ directory = g_hash_table_lookup (directories,
+ location);
+ if (directory != NULL)
+ {
+ caja_directory_ref (directory);
+ }
+ else if (create)
+ {
+ /* Create a new directory object instead. */
+ directory = caja_directory_new (location);
+ if (directory == NULL)
+ {
+ return NULL;
+ }
+
+ /* Put it in the hash table. */
+ g_hash_table_insert (directories,
+ directory->details->location,
+ directory);
+ }
+
+ return directory;
+}
+
+CajaDirectory *
+caja_directory_get (GFile *location)
+{
+ if (location == NULL)
+ {
+ return NULL;
+ }
+
+ return caja_directory_get_internal (location, TRUE);
+}
+
+CajaDirectory *
+caja_directory_get_existing (GFile *location)
+{
+ if (location == NULL)
+ {
+ return NULL;
+ }
+
+ return caja_directory_get_internal (location, FALSE);
+}
+
+
+CajaDirectory *
+caja_directory_get_by_uri (const char *uri)
+{
+ CajaDirectory *directory;
+ GFile *location;
+
+ if (uri == NULL)
+ {
+ return NULL;
+ }
+
+ location = g_file_new_for_uri (uri);
+
+ directory = caja_directory_get_internal (location, TRUE);
+ g_object_unref (location);
+ return directory;
+}
+
+CajaDirectory *
+caja_directory_get_for_file (CajaFile *file)
+{
+ char *uri;
+ CajaDirectory *directory;
+
+ g_return_val_if_fail (CAJA_IS_FILE (file), NULL);
+
+ uri = caja_file_get_uri (file);
+ directory = caja_directory_get_by_uri (uri);
+ g_free (uri);
+ return directory;
+}
+
+/* Returns a reffed CajaFile object for this directory.
+ */
+CajaFile *
+caja_directory_get_corresponding_file (CajaDirectory *directory)
+{
+ CajaFile *file;
+ char *uri;
+
+ file = caja_directory_get_existing_corresponding_file (directory);
+ if (file == NULL)
+ {
+ uri = caja_directory_get_uri (directory);
+ file = caja_file_get_by_uri (uri);
+ g_free (uri);
+ }
+
+ return file;
+}
+
+/* Returns a reffed CajaFile object for this directory, but only if the
+ * CajaFile object has already been created.
+ */
+CajaFile *
+caja_directory_get_existing_corresponding_file (CajaDirectory *directory)
+{
+ CajaFile *file;
+ char *uri;
+
+ file = directory->details->as_file;
+ if (file != NULL)
+ {
+ caja_file_ref (file);
+ return file;
+ }
+
+ uri = caja_directory_get_uri (directory);
+ file = caja_file_get_existing_by_uri (uri);
+ g_free (uri);
+ return file;
+}
+
+/* caja_directory_get_name_for_self_as_new_file:
+ *
+ * Get a name to display for the file representing this
+ * directory. This is called only when there's no VFS
+ * directory for this CajaDirectory.
+ */
+char *
+caja_directory_get_name_for_self_as_new_file (CajaDirectory *directory)
+{
+ g_return_val_if_fail (CAJA_IS_DIRECTORY (directory), NULL);
+
+ return EEL_CALL_METHOD_WITH_RETURN_VALUE
+ (CAJA_DIRECTORY_CLASS, directory,
+ get_name_for_self_as_new_file, (directory));
+}
+
+static char *
+real_get_name_for_self_as_new_file (CajaDirectory *directory)
+{
+ char *directory_uri;
+ char *name, *colon;
+
+ directory_uri = caja_directory_get_uri (directory);
+
+ colon = strchr (directory_uri, ':');
+ if (colon == NULL || colon == directory_uri)
+ {
+ name = g_strdup (directory_uri);
+ }
+ else
+ {
+ name = g_strndup (directory_uri, colon - directory_uri);
+ }
+ g_free (directory_uri);
+
+ return name;
+}
+
+char *
+caja_directory_get_uri (CajaDirectory *directory)
+{
+ g_return_val_if_fail (CAJA_IS_DIRECTORY (directory), NULL);
+
+ return g_file_get_uri (directory->details->location);
+}
+
+GFile *
+caja_directory_get_location (CajaDirectory *directory)
+{
+ g_return_val_if_fail (CAJA_IS_DIRECTORY (directory), NULL);
+
+ return g_object_ref (directory->details->location);
+}
+
+static CajaDirectory *
+caja_directory_new (GFile *location)
+{
+ CajaDirectory *directory;
+ char *uri;
+
+ uri = g_file_get_uri (location);
+
+ if (eel_uri_is_desktop (uri))
+ {
+ directory = CAJA_DIRECTORY (g_object_new (CAJA_TYPE_DESKTOP_DIRECTORY, NULL));
+ }
+ else if (eel_uri_is_search (uri))
+ {
+ directory = CAJA_DIRECTORY (g_object_new (CAJA_TYPE_SEARCH_DIRECTORY, NULL));
+ }
+ else if (g_str_has_suffix (uri, CAJA_SAVED_SEARCH_EXTENSION))
+ {
+ directory = CAJA_DIRECTORY (caja_search_directory_new_from_saved_search (uri));
+ }
+ else
+ {
+ directory = CAJA_DIRECTORY (g_object_new (CAJA_TYPE_VFS_DIRECTORY, NULL));
+ }
+
+ set_directory_location (directory, location);
+
+ g_free (uri);
+
+ return directory;
+}
+
+gboolean
+caja_directory_is_local (CajaDirectory *directory)
+{
+ g_return_val_if_fail (CAJA_IS_DIRECTORY (directory), FALSE);
+
+ if (directory->details->location == NULL)
+ {
+ return TRUE;
+ }
+
+ return caja_directory_is_in_trash (directory) ||
+ g_file_is_native (directory->details->location);
+}
+
+gboolean
+caja_directory_is_in_trash (CajaDirectory *directory)
+{
+ g_assert (CAJA_IS_DIRECTORY (directory));
+
+ if (directory->details->location == NULL)
+ {
+ return FALSE;
+ }
+
+ return g_file_has_uri_scheme (directory->details->location, "trash");
+}
+
+gboolean
+caja_directory_are_all_files_seen (CajaDirectory *directory)
+{
+ g_return_val_if_fail (CAJA_IS_DIRECTORY (directory), FALSE);
+
+ return EEL_CALL_METHOD_WITH_RETURN_VALUE
+ (CAJA_DIRECTORY_CLASS, directory,
+ are_all_files_seen, (directory));
+}
+
+static void
+add_to_hash_table (CajaDirectory *directory, CajaFile *file, GList *node)
+{
+ const char *name;
+
+ name = eel_ref_str_peek (file->details->name);
+
+ g_assert (node != NULL);
+ g_assert (g_hash_table_lookup (directory->details->file_hash,
+ name) == NULL);
+ g_hash_table_insert (directory->details->file_hash, (char *) name, node);
+}
+
+static GList *
+extract_from_hash_table (CajaDirectory *directory, CajaFile *file)
+{
+ const char *name;
+ GList *node;
+
+ name = eel_ref_str_peek (file->details->name);
+ if (name == NULL)
+ {
+ return NULL;
+ }
+
+ /* Find the list node in the hash table. */
+ node = g_hash_table_lookup (directory->details->file_hash, name);
+ g_hash_table_remove (directory->details->file_hash, name);
+
+ return node;
+}
+
+void
+caja_directory_add_file (CajaDirectory *directory, CajaFile *file)
+{
+ GList *node;
+ gboolean add_to_work_queue;
+
+ g_assert (CAJA_IS_DIRECTORY (directory));
+ g_assert (CAJA_IS_FILE (file));
+ g_assert (file->details->name != NULL);
+
+ /* Add to list. */
+ node = g_list_prepend (directory->details->file_list, file);
+ directory->details->file_list = node;
+
+ /* Add to hash table. */
+ add_to_hash_table (directory, file, node);
+
+ directory->details->confirmed_file_count++;
+
+ add_to_work_queue = FALSE;
+ if (caja_directory_is_file_list_monitored (directory))
+ {
+ /* Ref if we are monitoring, since monitoring owns the file list. */
+ caja_file_ref (file);
+ add_to_work_queue = TRUE;
+ }
+ else if (caja_directory_has_active_request_for_file (directory, file))
+ {
+ /* We're waiting for the file in a call_when_ready. Make sure
+ we add the file to the work queue so that said waiter won't
+ wait forever for e.g. all files in the directory to be done */
+ add_to_work_queue = TRUE;
+ }
+
+ if (add_to_work_queue)
+ {
+ caja_directory_add_file_to_work_queue (directory, file);
+ }
+}
+
+void
+caja_directory_remove_file (CajaDirectory *directory, CajaFile *file)
+{
+ GList *node;
+
+ g_assert (CAJA_IS_DIRECTORY (directory));
+ g_assert (CAJA_IS_FILE (file));
+ g_assert (file->details->name != NULL);
+
+ /* Find the list node in the hash table. */
+ node = extract_from_hash_table (directory, file);
+ g_assert (node != NULL);
+ g_assert (node->data == file);
+
+ /* Remove the item from the list. */
+ directory->details->file_list = g_list_remove_link
+ (directory->details->file_list, node);
+ g_list_free_1 (node);
+
+ caja_directory_remove_file_from_work_queue (directory, file);
+
+ if (!file->details->unconfirmed)
+ {
+ directory->details->confirmed_file_count--;
+ }
+
+ /* Unref if we are monitoring. */
+ if (caja_directory_is_file_list_monitored (directory))
+ {
+ caja_file_unref (file);
+ }
+}
+
+#define CAJA_DIRECTORY_FILE_LIST_DEFAULT_LIMIT 4000
+
+gboolean
+caja_directory_file_list_length_reached (CajaDirectory *directory)
+{
+ static gboolean inited = FALSE;
+ static int directory_limit = 0;
+
+ if (!inited)
+ {
+ eel_preferences_add_auto_integer
+ ("/apps/caja/preferences/directory_limit",
+ &directory_limit);
+ inited = TRUE;
+ }
+ if (directory_limit < 0) /* unlimited */
+ {
+ return FALSE;
+ }
+ if (directory_limit == 0) /* dead mateconfd */
+ {
+ directory_limit = CAJA_DIRECTORY_FILE_LIST_DEFAULT_LIMIT;
+ }
+
+ return directory->details->confirmed_file_count >= directory_limit;
+}
+
+GList *
+caja_directory_begin_file_name_change (CajaDirectory *directory,
+ CajaFile *file)
+{
+ /* Find the list node in the hash table. */
+ return extract_from_hash_table (directory, file);
+}
+
+void
+caja_directory_end_file_name_change (CajaDirectory *directory,
+ CajaFile *file,
+ GList *node)
+{
+ /* Add the list node to the hash table. */
+ if (node != NULL)
+ {
+ add_to_hash_table (directory, file, node);
+ }
+}
+
+CajaFile *
+caja_directory_find_file_by_name (CajaDirectory *directory,
+ const char *name)
+{
+ GList *node;
+
+ g_return_val_if_fail (CAJA_IS_DIRECTORY (directory), NULL);
+ g_return_val_if_fail (name != NULL, NULL);
+
+ node = g_hash_table_lookup (directory->details->file_hash,
+ name);
+ return node == NULL ? NULL : CAJA_FILE (node->data);
+}
+
+/* "." for the directory-as-file, otherwise the filename */
+CajaFile *
+caja_directory_find_file_by_internal_filename (CajaDirectory *directory,
+ const char *internal_filename)
+{
+ CajaFile *result;
+
+ if (eel_strcmp (internal_filename, ".") == 0)
+ {
+ result = caja_directory_get_existing_corresponding_file (directory);
+ if (result != NULL)
+ {
+ caja_file_unref (result);
+ }
+ }
+ else
+ {
+ result = caja_directory_find_file_by_name (directory, internal_filename);
+ }
+
+ return result;
+}
+
+void
+caja_directory_emit_files_added (CajaDirectory *directory,
+ GList *added_files)
+{
+ if (added_files != NULL)
+ {
+ g_signal_emit (directory,
+ signals[FILES_ADDED], 0,
+ added_files);
+ }
+}
+
+void
+caja_directory_emit_files_changed (CajaDirectory *directory,
+ GList *changed_files)
+{
+ if (changed_files != NULL)
+ {
+ g_signal_emit (directory,
+ signals[FILES_CHANGED], 0,
+ changed_files);
+ }
+}
+
+void
+caja_directory_emit_change_signals (CajaDirectory *directory,
+ GList *changed_files)
+{
+ GList *p;
+
+ for (p = changed_files; p != NULL; p = p->next)
+ {
+ caja_file_emit_changed (p->data);
+ }
+ caja_directory_emit_files_changed (directory, changed_files);
+}
+
+void
+caja_directory_emit_done_loading (CajaDirectory *directory)
+{
+ g_signal_emit (directory,
+ signals[DONE_LOADING], 0);
+}
+
+void
+caja_directory_emit_load_error (CajaDirectory *directory,
+ GError *error)
+{
+ g_signal_emit (directory,
+ signals[LOAD_ERROR], 0,
+ error);
+}
+
+/* Return a directory object for this one's parent. */
+static CajaDirectory *
+get_parent_directory (GFile *location)
+{
+ CajaDirectory *directory;
+ GFile *parent;
+
+ parent = g_file_get_parent (location);
+ if (parent)
+ {
+ directory = caja_directory_get_internal (parent, TRUE);
+ g_object_unref (parent);
+ return directory;
+ }
+ return NULL;
+}
+
+/* If a directory object exists for this one's parent, then
+ * return it, otherwise return NULL.
+ */
+static CajaDirectory *
+get_parent_directory_if_exists (GFile *location)
+{
+ CajaDirectory *directory;
+ GFile *parent;
+
+ parent = g_file_get_parent (location);
+ if (parent)
+ {
+ directory = caja_directory_get_internal (parent, FALSE);
+ g_object_unref (parent);
+ return directory;
+ }
+ return NULL;
+}
+
+static void
+hash_table_list_prepend (GHashTable *table, gconstpointer key, gpointer data)
+{
+ GList *list;
+
+ list = g_hash_table_lookup (table, key);
+ list = g_list_prepend (list, data);
+ g_hash_table_insert (table, (gpointer) key, list);
+}
+
+static void
+call_files_added_free_list (gpointer key, gpointer value, gpointer user_data)
+{
+ g_assert (CAJA_IS_DIRECTORY (key));
+ g_assert (value != NULL);
+ g_assert (user_data == NULL);
+
+ g_signal_emit (key,
+ signals[FILES_ADDED], 0,
+ value);
+ g_list_free (value);
+}
+
+static void
+call_files_changed_common (CajaDirectory *directory, GList *file_list)
+{
+ GList *node;
+ CajaFile *file;
+
+ for (node = file_list; node != NULL; node = node->next)
+ {
+ file = node->data;
+ if (file->details->directory == directory)
+ {
+ caja_directory_add_file_to_work_queue (directory,
+ file);
+ }
+ }
+ caja_directory_async_state_changed (directory);
+ caja_directory_emit_change_signals (directory, file_list);
+}
+
+static void
+call_files_changed_free_list (gpointer key, gpointer value, gpointer user_data)
+{
+ g_assert (value != NULL);
+ g_assert (user_data == NULL);
+
+ call_files_changed_common (CAJA_DIRECTORY (key), value);
+ g_list_free (value);
+}
+
+static void
+call_files_changed_unref_free_list (gpointer key, gpointer value, gpointer user_data)
+{
+ g_assert (value != NULL);
+ g_assert (user_data == NULL);
+
+ call_files_changed_common (CAJA_DIRECTORY (key), value);
+ caja_file_list_free (value);
+}
+
+static void
+call_get_file_info_free_list (gpointer key, gpointer value, gpointer user_data)
+{
+ CajaDirectory *directory;
+ GList *files;
+
+ g_assert (CAJA_IS_DIRECTORY (key));
+ g_assert (value != NULL);
+ g_assert (user_data == NULL);
+
+ directory = key;
+ files = value;
+
+ caja_directory_get_info_for_new_files (directory, files);
+ g_list_foreach (files, (GFunc) g_object_unref, NULL);
+ g_list_free (files);
+}
+
+static void
+invalidate_count_and_unref (gpointer key, gpointer value, gpointer user_data)
+{
+ g_assert (CAJA_IS_DIRECTORY (key));
+ g_assert (value == key);
+ g_assert (user_data == NULL);
+
+ caja_directory_invalidate_count_and_mime_list (key);
+ caja_directory_unref (key);
+}
+
+static void
+collect_parent_directories (GHashTable *hash_table, CajaDirectory *directory)
+{
+ g_assert (hash_table != NULL);
+ g_assert (CAJA_IS_DIRECTORY (directory));
+
+ if (g_hash_table_lookup (hash_table, directory) == NULL)
+ {
+ caja_directory_ref (directory);
+ g_hash_table_insert (hash_table, directory, directory);
+ }
+}
+
+void
+caja_directory_notify_files_added (GList *files)
+{
+ GHashTable *added_lists;
+ GList *p;
+ CajaDirectory *directory;
+ GHashTable *parent_directories;
+ CajaFile *file;
+ GFile *location, *parent;
+
+ /* Make a list of added files in each directory. */
+ added_lists = g_hash_table_new (NULL, NULL);
+
+ /* Make a list of parent directories that will need their counts updated. */
+ parent_directories = g_hash_table_new (NULL, NULL);
+
+ for (p = files; p != NULL; p = p->next)
+ {
+ location = p->data;
+
+ /* See if the directory is already known. */
+ directory = get_parent_directory_if_exists (location);
+ if (directory == NULL)
+ {
+ /* In case the directory is not being
+ * monitored, but the corresponding file is,
+ * we must invalidate it's item count.
+ */
+
+
+ file = NULL;
+ parent = g_file_get_parent (location);
+ if (parent)
+ {
+ file = caja_file_get_existing (parent);
+ g_object_unref (parent);
+ }
+
+ if (file != NULL)
+ {
+ caja_file_invalidate_count_and_mime_list (file);
+ caja_file_unref (file);
+ }
+
+ continue;
+ }
+
+ collect_parent_directories (parent_directories, directory);
+
+ /* If no one is monitoring files in the directory, nothing to do. */
+ if (!caja_directory_is_file_list_monitored (directory))
+ {
+ caja_directory_unref (directory);
+ continue;
+ }
+
+ file = caja_file_get_existing (location);
+ /* We check is_added here, because the file could have been added
+ * to the directory by a caja_file_get() but not gotten
+ * files_added emitted
+ */
+ if (file && file->details->is_added)
+ {
+ /* A file already exists, it was probably renamed.
+ * If it was renamed this could be ignored, but
+ * queue a change just in case */
+ caja_file_changed (file);
+ caja_file_unref (file);
+ }
+ else
+ {
+ hash_table_list_prepend (added_lists,
+ directory,
+ g_object_ref (location));
+ }
+ caja_directory_unref (directory);
+ }
+
+ /* Now get file info for the new files. This creates CajaFile
+ * objects for the new files, and sends out a files_added signal.
+ */
+ g_hash_table_foreach (added_lists, call_get_file_info_free_list, NULL);
+ g_hash_table_destroy (added_lists);
+
+ /* Invalidate count for each parent directory. */
+ g_hash_table_foreach (parent_directories, invalidate_count_and_unref, NULL);
+ g_hash_table_destroy (parent_directories);
+}
+
+static void
+g_file_pair_free (GFilePair *pair)
+{
+ g_object_unref (pair->to);
+ g_object_unref (pair->from);
+ g_free (pair);
+}
+
+static GList *
+uri_pairs_to_file_pairs (GList *uri_pairs)
+{
+ GList *l, *file_pair_list;
+ GFilePair *file_pair;
+ URIPair *uri_pair;
+
+ file_pair_list = NULL;
+
+ for (l = uri_pairs; l != NULL; l = l->next)
+ {
+ uri_pair = l->data;
+ file_pair = g_new (GFilePair, 1);
+ file_pair->from = g_file_new_for_uri (uri_pair->from_uri);
+ file_pair->to = g_file_new_for_uri (uri_pair->to_uri);
+
+ file_pair_list = g_list_prepend (file_pair_list, file_pair);
+ }
+ return g_list_reverse (file_pair_list);
+}
+
+void
+caja_directory_notify_files_added_by_uri (GList *uris)
+{
+ GList *files;
+
+ files = caja_file_list_from_uris (uris);
+ caja_directory_notify_files_added (files);
+ eel_g_object_list_free (files);
+}
+
+void
+caja_directory_notify_files_changed (GList *files)
+{
+ GHashTable *changed_lists;
+ GList *node;
+ GFile *location;
+ CajaFile *file;
+
+ /* Make a list of changed files in each directory. */
+ changed_lists = g_hash_table_new (NULL, NULL);
+
+ /* Go through all the notifications. */
+ for (node = files; node != NULL; node = node->next)
+ {
+ location = node->data;
+
+ /* Find the file. */
+ file = caja_file_get_existing (location);
+ if (file != NULL)
+ {
+ /* Tell it to re-get info now, and later emit
+ * a changed signal.
+ */
+ file->details->file_info_is_up_to_date = FALSE;
+ file->details->top_left_text_is_up_to_date = FALSE;
+ file->details->link_info_is_up_to_date = FALSE;
+ caja_file_invalidate_extension_info_internal (file);
+
+ hash_table_list_prepend (changed_lists,
+ file->details->directory,
+ file);
+ }
+ }
+
+ /* Now send out the changed signals. */
+ g_hash_table_foreach (changed_lists, call_files_changed_unref_free_list, NULL);
+ g_hash_table_destroy (changed_lists);
+}
+
+void
+caja_directory_notify_files_changed_by_uri (GList *uris)
+{
+ GList *files;
+
+ files = caja_file_list_from_uris (uris);
+ caja_directory_notify_files_changed (files);
+ eel_g_object_list_free (files);
+}
+
+void
+caja_directory_notify_files_removed (GList *files)
+{
+ GHashTable *changed_lists;
+ GList *p;
+ CajaDirectory *directory;
+ GHashTable *parent_directories;
+ CajaFile *file;
+ GFile *location;
+
+ /* Make a list of changed files in each directory. */
+ changed_lists = g_hash_table_new (NULL, NULL);
+
+ /* Make a list of parent directories that will need their counts updated. */
+ parent_directories = g_hash_table_new (NULL, NULL);
+
+ /* Go through all the notifications. */
+ for (p = files; p != NULL; p = p->next)
+ {
+ location = p->data;
+
+ /* Update file count for parent directory if anyone might care. */
+ directory = get_parent_directory_if_exists (location);
+ if (directory != NULL)
+ {
+ collect_parent_directories (parent_directories, directory);
+ caja_directory_unref (directory);
+ }
+
+ /* Find the file. */
+ file = caja_file_get_existing (location);
+ if (file != NULL && !caja_file_rename_in_progress (file))
+ {
+ /* Mark it gone and prepare to send the changed signal. */
+ caja_file_mark_gone (file);
+ hash_table_list_prepend (changed_lists,
+ file->details->directory,
+ caja_file_ref (file));
+ }
+ caja_file_unref (file);
+ }
+
+ /* Now send out the changed signals. */
+ g_hash_table_foreach (changed_lists, call_files_changed_unref_free_list, NULL);
+ g_hash_table_destroy (changed_lists);
+
+ /* Invalidate count for each parent directory. */
+ g_hash_table_foreach (parent_directories, invalidate_count_and_unref, NULL);
+ g_hash_table_destroy (parent_directories);
+}
+
+void
+caja_directory_notify_files_removed_by_uri (GList *uris)
+{
+ GList *files;
+
+ files = caja_file_list_from_uris (uris);
+ caja_directory_notify_files_changed (files);
+ eel_g_object_list_free (files);
+}
+
+static void
+set_directory_location (CajaDirectory *directory,
+ GFile *location)
+{
+ if (directory->details->location)
+ {
+ g_object_unref (directory->details->location);
+ }
+ directory->details->location = g_object_ref (location);
+
+}
+
+static void
+change_directory_location (CajaDirectory *directory,
+ GFile *new_location)
+{
+ /* I believe it's impossible for a self-owned file/directory
+ * to be moved. But if that did somehow happen, this function
+ * wouldn't do enough to handle it.
+ */
+ g_assert (directory->details->as_file == NULL);
+
+ g_hash_table_remove (directories,
+ directory->details->location);
+
+ set_directory_location (directory, new_location);
+
+ g_hash_table_insert (directories,
+ directory->details->location,
+ directory);
+}
+
+typedef struct
+{
+ GFile *container;
+ GList *directories;
+} CollectData;
+
+static void
+collect_directories_by_container (gpointer key, gpointer value, gpointer callback_data)
+{
+ CajaDirectory *directory;
+ CollectData *collect_data;
+ GFile *location;
+
+ location = (GFile *) key;
+ directory = CAJA_DIRECTORY (value);
+ collect_data = (CollectData *) callback_data;
+
+ if (g_file_has_prefix (location, collect_data->container) ||
+ g_file_equal (collect_data->container, location))
+ {
+ caja_directory_ref (directory);
+ collect_data->directories =
+ g_list_prepend (collect_data->directories,
+ directory);
+ }
+}
+
+static GList *
+caja_directory_moved_internal (GFile *old_location,
+ GFile *new_location)
+{
+ CollectData collection;
+ CajaDirectory *directory;
+ GList *node, *affected_files;
+ GFile *new_directory_location;
+ char *relative_path;
+
+ collection.container = old_location;
+ collection.directories = NULL;
+
+ g_hash_table_foreach (directories,
+ collect_directories_by_container,
+ &collection);
+
+ affected_files = NULL;
+
+ for (node = collection.directories; node != NULL; node = node->next)
+ {
+ directory = CAJA_DIRECTORY (node->data);
+ new_directory_location = NULL;
+
+ if (g_file_equal (directory->details->location, old_location))
+ {
+ new_directory_location = g_object_ref (new_location);
+ }
+ else
+ {
+ relative_path = g_file_get_relative_path (old_location,
+ directory->details->location);
+ if (relative_path != NULL)
+ {
+ new_directory_location = g_file_resolve_relative_path (new_location, relative_path);
+ g_free (relative_path);
+
+ }
+ }
+
+ if (new_directory_location)
+ {
+ change_directory_location (directory, new_directory_location);
+ g_object_unref (new_directory_location);
+
+ /* Collect affected files. */
+ if (directory->details->as_file != NULL)
+ {
+ affected_files = g_list_prepend
+ (affected_files,
+ caja_file_ref (directory->details->as_file));
+ }
+ affected_files = g_list_concat
+ (affected_files,
+ caja_file_list_copy (directory->details->file_list));
+ }
+
+ caja_directory_unref (directory);
+ }
+
+ g_list_free (collection.directories);
+
+ return affected_files;
+}
+
+void
+caja_directory_moved (const char *old_uri,
+ const char *new_uri)
+{
+ GList *list, *node;
+ GHashTable *hash;
+ CajaFile *file;
+ GFile *old_location;
+ GFile *new_location;
+
+ hash = g_hash_table_new (NULL, NULL);
+
+ old_location = g_file_new_for_uri (old_uri);
+ new_location = g_file_new_for_uri (new_uri);
+
+ list = caja_directory_moved_internal (old_location, new_location);
+ for (node = list; node != NULL; node = node->next)
+ {
+ file = CAJA_FILE (node->data);
+ hash_table_list_prepend (hash,
+ file->details->directory,
+ caja_file_ref (file));
+ }
+ caja_file_list_free (list);
+
+ g_object_unref (old_location);
+ g_object_unref (new_location);
+
+ g_hash_table_foreach (hash, call_files_changed_unref_free_list, NULL);
+ g_hash_table_destroy (hash);
+}
+
+void
+caja_directory_notify_files_moved (GList *file_pairs)
+{
+ GList *p, *affected_files, *node;
+ GFilePair *pair;
+ CajaFile *file;
+ CajaDirectory *old_directory, *new_directory;
+ GHashTable *parent_directories;
+ GList *new_files_list, *unref_list;
+ GHashTable *added_lists, *changed_lists;
+ char *name;
+ CajaFileAttributes cancel_attributes;
+ GFile *to_location, *from_location;
+
+ /* Make a list of added and changed files in each directory. */
+ new_files_list = NULL;
+ added_lists = g_hash_table_new (NULL, NULL);
+ changed_lists = g_hash_table_new (NULL, NULL);
+ unref_list = NULL;
+
+ /* Make a list of parent directories that will need their counts updated. */
+ parent_directories = g_hash_table_new (NULL, NULL);
+
+ cancel_attributes = caja_file_get_all_attributes ();
+
+ for (p = file_pairs; p != NULL; p = p->next)
+ {
+ pair = p->data;
+ from_location = pair->from;
+ to_location = pair->to;
+
+ /* Handle overwriting a file. */
+ file = caja_file_get_existing (to_location);
+ if (file != NULL)
+ {
+ /* Mark it gone and prepare to send the changed signal. */
+ caja_file_mark_gone (file);
+ new_directory = file->details->directory;
+ hash_table_list_prepend (changed_lists,
+ new_directory,
+ file);
+ collect_parent_directories (parent_directories,
+ new_directory);
+ }
+
+ /* Update any directory objects that are affected. */
+ affected_files = caja_directory_moved_internal (from_location,
+ to_location);
+ for (node = affected_files; node != NULL; node = node->next)
+ {
+ file = CAJA_FILE (node->data);
+ hash_table_list_prepend (changed_lists,
+ file->details->directory,
+ file);
+ }
+ unref_list = g_list_concat (unref_list, affected_files);
+
+ /* Move an existing file. */
+ file = caja_file_get_existing (from_location);
+ if (file == NULL)
+ {
+ /* Handle this as if it was a new file. */
+ new_files_list = g_list_prepend (new_files_list,
+ to_location);
+ }
+ else
+ {
+ /* Handle notification in the old directory. */
+ old_directory = file->details->directory;
+ collect_parent_directories (parent_directories, old_directory);
+
+ /* Cancel loading of attributes in the old directory */
+ caja_directory_cancel_loading_file_attributes
+ (old_directory, file, cancel_attributes);
+
+ /* Locate the new directory. */
+ new_directory = get_parent_directory (to_location);
+ collect_parent_directories (parent_directories, new_directory);
+ /* We can unref now -- new_directory is in the
+ * parent directories list so it will be
+ * around until the end of this function
+ * anyway.
+ */
+ caja_directory_unref (new_directory);
+
+ /* Update the file's name and directory. */
+ name = g_file_get_basename (to_location);
+ caja_file_update_name_and_directory
+ (file, name, new_directory);
+ g_free (name);
+
+ /* Update file attributes */
+ caja_file_invalidate_attributes (file, CAJA_FILE_ATTRIBUTE_INFO);
+
+ hash_table_list_prepend (changed_lists,
+ old_directory,
+ file);
+ if (old_directory != new_directory)
+ {
+ hash_table_list_prepend (added_lists,
+ new_directory,
+ file);
+ }
+
+ /* Unref each file once to balance out caja_file_get_by_uri. */
+ unref_list = g_list_prepend (unref_list, file);
+ }
+ }
+
+ /* Now send out the changed and added signals for existing file objects. */
+ g_hash_table_foreach (changed_lists, call_files_changed_free_list, NULL);
+ g_hash_table_destroy (changed_lists);
+ g_hash_table_foreach (added_lists, call_files_added_free_list, NULL);
+ g_hash_table_destroy (added_lists);
+
+ /* Let the file objects go. */
+ caja_file_list_free (unref_list);
+
+ /* Invalidate count for each parent directory. */
+ g_hash_table_foreach (parent_directories, invalidate_count_and_unref, NULL);
+ g_hash_table_destroy (parent_directories);
+
+ /* Separate handling for brand new file objects. */
+ caja_directory_notify_files_added (new_files_list);
+ g_list_free (new_files_list);
+}
+
+void
+caja_directory_notify_files_moved_by_uri (GList *uri_pairs)
+{
+ GList *file_pairs;
+
+ file_pairs = uri_pairs_to_file_pairs (uri_pairs);
+ caja_directory_notify_files_moved (file_pairs);
+ g_list_foreach (file_pairs, (GFunc)g_file_pair_free, NULL);
+ g_list_free (file_pairs);
+}
+
+void
+caja_directory_schedule_position_set (GList *position_setting_list)
+{
+ GList *p;
+ const CajaFileChangesQueuePosition *item;
+ CajaFile *file;
+ char str[64];
+ time_t now;
+
+ time (&now);
+
+ for (p = position_setting_list; p != NULL; p = p->next)
+ {
+ item = (CajaFileChangesQueuePosition *) p->data;
+
+ file = caja_file_get (item->location);
+
+ if (item->set)
+ {
+ g_snprintf (str, sizeof (str), "%d,%d", item->point.x, item->point.y);
+ }
+ else
+ {
+ str[0] = 0;
+ }
+ caja_file_set_metadata
+ (file,
+ CAJA_METADATA_KEY_ICON_POSITION,
+ NULL,
+ str);
+
+ if (item->set)
+ {
+ caja_file_set_time_metadata
+ (file,
+ CAJA_METADATA_KEY_ICON_POSITION_TIMESTAMP,
+ now);
+ }
+ else
+ {
+ caja_file_set_time_metadata
+ (file,
+ CAJA_METADATA_KEY_ICON_POSITION_TIMESTAMP,
+ UNDEFINED_TIME);
+ }
+
+ if (item->set)
+ {
+ g_snprintf (str, sizeof (str), "%d", item->screen);
+ }
+ else
+ {
+ str[0] = 0;
+ }
+ caja_file_set_metadata
+ (file,
+ CAJA_METADATA_KEY_SCREEN,
+ NULL,
+ str);
+
+ caja_file_unref (file);
+ }
+}
+
+gboolean
+caja_directory_contains_file (CajaDirectory *directory,
+ CajaFile *file)
+{
+ g_return_val_if_fail (CAJA_IS_DIRECTORY (directory), FALSE);
+ g_return_val_if_fail (CAJA_IS_FILE (file), FALSE);
+
+ if (caja_file_is_gone (file))
+ {
+ return FALSE;
+ }
+
+ return EEL_CALL_METHOD_WITH_RETURN_VALUE
+ (CAJA_DIRECTORY_CLASS, directory,
+ contains_file, (directory, file));
+}
+
+char *
+caja_directory_get_file_uri (CajaDirectory *directory,
+ const char *file_name)
+{
+ GFile *child;
+ char *result;
+
+ g_return_val_if_fail (CAJA_IS_DIRECTORY (directory), NULL);
+ g_return_val_if_fail (file_name != NULL, NULL);
+
+ result = NULL;
+
+ child = g_file_get_child (directory->details->location, file_name);
+ result = g_file_get_uri (child);
+ g_object_unref (child);
+
+ return result;
+}
+
+void
+caja_directory_call_when_ready (CajaDirectory *directory,
+ CajaFileAttributes file_attributes,
+ gboolean wait_for_all_files,
+ CajaDirectoryCallback callback,
+ gpointer callback_data)
+{
+ g_return_if_fail (CAJA_IS_DIRECTORY (directory));
+ g_return_if_fail (callback != NULL);
+
+ EEL_CALL_METHOD
+ (CAJA_DIRECTORY_CLASS, directory,
+ call_when_ready, (directory, file_attributes, wait_for_all_files,
+ callback, callback_data));
+}
+
+void
+caja_directory_cancel_callback (CajaDirectory *directory,
+ CajaDirectoryCallback callback,
+ gpointer callback_data)
+{
+ g_return_if_fail (CAJA_IS_DIRECTORY (directory));
+ g_return_if_fail (callback != NULL);
+
+ EEL_CALL_METHOD
+ (CAJA_DIRECTORY_CLASS, directory,
+ cancel_callback, (directory, callback, callback_data));
+}
+
+void
+caja_directory_file_monitor_add (CajaDirectory *directory,
+ gconstpointer client,
+ gboolean monitor_hidden_files,
+ gboolean monitor_backup_files,
+ CajaFileAttributes file_attributes,
+ CajaDirectoryCallback callback,
+ gpointer callback_data)
+{
+ g_return_if_fail (CAJA_IS_DIRECTORY (directory));
+ g_return_if_fail (client != NULL);
+
+ EEL_CALL_METHOD
+ (CAJA_DIRECTORY_CLASS, directory,
+ file_monitor_add, (directory, client,
+ monitor_hidden_files,
+ monitor_backup_files,
+ file_attributes,
+ callback, callback_data));
+}
+
+void
+caja_directory_file_monitor_remove (CajaDirectory *directory,
+ gconstpointer client)
+{
+ g_return_if_fail (CAJA_IS_DIRECTORY (directory));
+ g_return_if_fail (client != NULL);
+
+ EEL_CALL_METHOD
+ (CAJA_DIRECTORY_CLASS, directory,
+ file_monitor_remove, (directory, client));
+}
+
+void
+caja_directory_force_reload (CajaDirectory *directory)
+{
+ g_return_if_fail (CAJA_IS_DIRECTORY (directory));
+
+ EEL_CALL_METHOD
+ (CAJA_DIRECTORY_CLASS, directory,
+ force_reload, (directory));
+}
+
+gboolean
+caja_directory_is_not_empty (CajaDirectory *directory)
+{
+ g_return_val_if_fail (CAJA_IS_DIRECTORY (directory), FALSE);
+
+ return EEL_CALL_METHOD_WITH_RETURN_VALUE
+ (CAJA_DIRECTORY_CLASS, directory,
+ is_not_empty, (directory));
+}
+
+static gboolean
+is_tentative (gpointer data, gpointer callback_data)
+{
+ CajaFile *file;
+
+ g_assert (callback_data == NULL);
+
+ file = CAJA_FILE (data);
+ /* Avoid returning files with !is_added, because these
+ * will later be sent with the files_added signal, and a
+ * user doing get_file_list + files_added monitoring will
+ * then see the file twice */
+ return !file->details->got_file_info || !file->details->is_added;
+}
+
+GList *
+caja_directory_get_file_list (CajaDirectory *directory)
+{
+ return EEL_CALL_METHOD_WITH_RETURN_VALUE
+ (CAJA_DIRECTORY_CLASS, directory,
+ get_file_list, (directory));
+}
+
+static GList *
+real_get_file_list (CajaDirectory *directory)
+{
+ GList *tentative_files, *non_tentative_files;
+
+ tentative_files = eel_g_list_partition
+ (g_list_copy (directory->details->file_list),
+ is_tentative, NULL, &non_tentative_files);
+ g_list_free (tentative_files);
+
+ caja_file_list_ref (non_tentative_files);
+ return non_tentative_files;
+}
+
+static gboolean
+real_is_editable (CajaDirectory *directory)
+{
+ return TRUE;
+}
+
+gboolean
+caja_directory_is_editable (CajaDirectory *directory)
+{
+ return EEL_CALL_METHOD_WITH_RETURN_VALUE
+ (CAJA_DIRECTORY_CLASS, directory,
+ is_editable, (directory));
+}
+
+GList *
+caja_directory_match_pattern (CajaDirectory *directory, const char *pattern)
+{
+ GList *files, *l, *ret;
+ GPatternSpec *spec;
+
+
+ ret = NULL;
+ spec = g_pattern_spec_new (pattern);
+
+ files = caja_directory_get_file_list (directory);
+ for (l = files; l; l = l->next)
+ {
+ CajaFile *file;
+ char *name;
+
+ file = CAJA_FILE (l->data);
+ name = caja_file_get_display_name (file);
+
+ if (g_pattern_match_string (spec, name))
+ {
+ ret = g_list_prepend(ret, caja_file_ref (file));
+ }
+
+ g_free (name);
+ }
+
+ g_pattern_spec_free (spec);
+ caja_file_list_free (files);
+
+ return ret;
+}
+
+/**
+ * caja_directory_list_ref
+ *
+ * Ref all the directories in a list.
+ * @list: GList of directories.
+ **/
+GList *
+caja_directory_list_ref (GList *list)
+{
+ g_list_foreach (list, (GFunc) caja_directory_ref, NULL);
+ return list;
+}
+
+/**
+ * caja_directory_list_unref
+ *
+ * Unref all the directories in a list.
+ * @list: GList of directories.
+ **/
+void
+caja_directory_list_unref (GList *list)
+{
+ g_list_foreach (list, (GFunc) caja_directory_unref, NULL);
+}
+
+/**
+ * caja_directory_list_free
+ *
+ * Free a list of directories after unrefing them.
+ * @list: GList of directories.
+ **/
+void
+caja_directory_list_free (GList *list)
+{
+ caja_directory_list_unref (list);
+ g_list_free (list);
+}
+
+/**
+ * caja_directory_list_copy
+ *
+ * Copy the list of directories, making a new ref of each,
+ * @list: GList of directories.
+ **/
+GList *
+caja_directory_list_copy (GList *list)
+{
+ return g_list_copy (caja_directory_list_ref (list));
+}
+
+static int
+compare_by_uri (CajaDirectory *a, CajaDirectory *b)
+{
+ char *uri_a, *uri_b;
+ int res;
+
+ uri_a = g_file_get_uri (a->details->location);
+ uri_b = g_file_get_uri (b->details->location);
+
+ res = strcmp (uri_a, uri_b);
+
+ g_free (uri_a);
+ g_free (uri_b);
+
+ return res;
+}
+
+static int
+compare_by_uri_cover (gconstpointer a, gconstpointer b)
+{
+ return compare_by_uri (CAJA_DIRECTORY (a), CAJA_DIRECTORY (b));
+}
+
+/**
+ * caja_directory_list_sort_by_uri
+ *
+ * Sort the list of directories by directory uri.
+ * @list: GList of directories.
+ **/
+GList *
+caja_directory_list_sort_by_uri (GList *list)
+{
+ return g_list_sort (list, compare_by_uri_cover);
+}
+
+gboolean
+caja_directory_is_desktop_directory (CajaDirectory *directory)
+{
+ if (directory->details->location == NULL)
+ {
+ return FALSE;
+ }
+
+ return caja_is_desktop_directory (directory->details->location);
+}
+
+#if !defined (CAJA_OMIT_SELF_CHECK)
+
+#include <eel/eel-debug.h>
+#include "caja-file-attributes.h"
+
+static int data_dummy;
+static gboolean got_files_flag;
+
+static void
+got_files_callback (CajaDirectory *directory, GList *files, gpointer callback_data)
+{
+ g_assert (CAJA_IS_DIRECTORY (directory));
+ g_assert (g_list_length (files) > 10);
+ g_assert (callback_data == &data_dummy);
+
+ got_files_flag = TRUE;
+}
+
+/* Return the number of extant CajaDirectories */
+int
+caja_directory_number_outstanding (void)
+{
+ return directories ? g_hash_table_size (directories) : 0;
+}
+
+void
+caja_self_check_directory (void)
+{
+ CajaDirectory *directory;
+ CajaFile *file;
+
+ directory = caja_directory_get_by_uri ("file:///etc");
+ file = caja_file_get_by_uri ("file:///etc/passwd");
+
+ EEL_CHECK_INTEGER_RESULT (g_hash_table_size (directories), 1);
+
+ caja_directory_file_monitor_add
+ (directory, &data_dummy,
+ TRUE, TRUE, 0, NULL, NULL);
+
+ /* FIXME: these need to be updated to the new metadata infrastructure
+ * as make check doesn't pass.
+ caja_file_set_metadata (file, "test", "default", "value");
+ EEL_CHECK_STRING_RESULT (caja_file_get_metadata (file, "test", "default"), "value");
+
+ caja_file_set_boolean_metadata (file, "test_boolean", TRUE, TRUE);
+ EEL_CHECK_BOOLEAN_RESULT (caja_file_get_boolean_metadata (file, "test_boolean", TRUE), TRUE);
+ caja_file_set_boolean_metadata (file, "test_boolean", TRUE, FALSE);
+ EEL_CHECK_BOOLEAN_RESULT (caja_file_get_boolean_metadata (file, "test_boolean", TRUE), FALSE);
+ EEL_CHECK_BOOLEAN_RESULT (caja_file_get_boolean_metadata (NULL, "test_boolean", TRUE), TRUE);
+
+ caja_file_set_integer_metadata (file, "test_integer", 0, 17);
+ EEL_CHECK_INTEGER_RESULT (caja_file_get_integer_metadata (file, "test_integer", 0), 17);
+ caja_file_set_integer_metadata (file, "test_integer", 0, -1);
+ EEL_CHECK_INTEGER_RESULT (caja_file_get_integer_metadata (file, "test_integer", 0), -1);
+ caja_file_set_integer_metadata (file, "test_integer", 42, 42);
+ EEL_CHECK_INTEGER_RESULT (caja_file_get_integer_metadata (file, "test_integer", 42), 42);
+ EEL_CHECK_INTEGER_RESULT (caja_file_get_integer_metadata (NULL, "test_integer", 42), 42);
+ EEL_CHECK_INTEGER_RESULT (caja_file_get_integer_metadata (file, "nonexistent_key", 42), 42);
+ */
+
+ EEL_CHECK_BOOLEAN_RESULT (caja_directory_get_by_uri ("file:///etc") == directory, TRUE);
+ caja_directory_unref (directory);
+
+ EEL_CHECK_BOOLEAN_RESULT (caja_directory_get_by_uri ("file:///etc/") == directory, TRUE);
+ caja_directory_unref (directory);
+
+ EEL_CHECK_BOOLEAN_RESULT (caja_directory_get_by_uri ("file:///etc////") == directory, TRUE);
+ caja_directory_unref (directory);
+
+ caja_file_unref (file);
+
+ caja_directory_file_monitor_remove (directory, &data_dummy);
+
+ caja_directory_unref (directory);
+
+ while (g_hash_table_size (directories) != 0)
+ {
+ gtk_main_iteration ();
+ }
+
+ EEL_CHECK_INTEGER_RESULT (g_hash_table_size (directories), 0);
+
+ directory = caja_directory_get_by_uri ("file:///etc");
+
+ got_files_flag = FALSE;
+
+ caja_directory_call_when_ready (directory,
+ CAJA_FILE_ATTRIBUTE_INFO |
+ CAJA_FILE_ATTRIBUTE_DEEP_COUNTS,
+ TRUE,
+ got_files_callback, &data_dummy);
+
+ while (!got_files_flag)
+ {
+ gtk_main_iteration ();
+ }
+
+ EEL_CHECK_BOOLEAN_RESULT (directory->details->file_list == NULL, TRUE);
+
+ EEL_CHECK_INTEGER_RESULT (g_hash_table_size (directories), 1);
+
+ file = caja_file_get_by_uri ("file:///etc/passwd");
+
+ /* EEL_CHECK_STRING_RESULT (caja_file_get_metadata (file, "test", "default"), "value"); */
+
+ caja_file_unref (file);
+
+ caja_directory_unref (directory);
+
+ EEL_CHECK_INTEGER_RESULT (g_hash_table_size (directories), 0);
+}
+
+#endif /* !CAJA_OMIT_SELF_CHECK */