The attached patch is meant to implement recursive file permission changes [1]. I'm eagerly awaiting feedback, in particular whether the GUI offers enough usability for you. [1] http://bugzilla.gnome.org/show_bug.cgi?id=44767 -- Christian Neumair <chris gnome-de org>
Index: src/file-manager/fm-properties-window.c =================================================================== RCS file: /cvs/gnome/nautilus/src/file-manager/fm-properties-window.c,v retrieving revision 1.226 diff -u -p -r1.226 fm-properties-window.c --- src/file-manager/fm-properties-window.c 20 Dec 2005 16:37:33 -0000 1.226 +++ src/file-manager/fm-properties-window.c 26 Dec 2005 00:24:04 -0000 @@ -68,7 +68,9 @@ #include <libgnomevfs/gnome-vfs.h> #include <libnautilus-extension/nautilus-property-page-provider.h> #include <libnautilus-private/nautilus-customization-data.h> +#include <libnautilus-private/nautilus-directory.h> #include <libnautilus-private/nautilus-entry.h> +#include <libnautilus-private/nautilus-file.h> #include <libnautilus-private/nautilus-file-attributes.h> #include <libnautilus-private/nautilus-desktop-icon-file.h> #include <libnautilus-private/nautilus-global-preferences.h> @@ -119,6 +121,9 @@ struct FMPropertiesWindowDetails { GList *permission_buttons; GHashTable *initial_permissions; + GtkWidget *apply_recursively_button; + GtkWidget *apply_to_combo; + GList *value_fields; GList *mime_list; @@ -175,6 +180,20 @@ static const GtkTargetEntry target_table { "x-special/gnome-reset-background", 0, TARGET_RESET_BACKGROUND } }; +typedef enum { + PERMISSIONS_CHANGE_SCOPE_SUBFOLDERS = 1 << 0, + PERMISSIONS_CHANGE_SCOPE_FILES = 1 << 1, +} PermissionsChangeScope; + +typedef struct { + FMPropertiesWindow *window; + GnomeVFSFilePermissions permission_mask; + gboolean is_on; + PermissionsChangeScope scope; + unsigned int ref; +} PermissionsChangeRequest; + + #define DIRECTORY_CONTENTS_UPDATE_INTERVAL 200 /* milliseconds */ #define FILES_UPDATE_INTERVAL 200 /* milliseconds */ #define STANDARD_EMBLEM_HEIGHT 52 @@ -185,10 +204,14 @@ static void file_changed_callback gpointer user_data); static void permission_button_update (FMPropertiesWindow *window, GtkToggleButton *button); +static void permission_change_callback (NautilusFile *file, + GnomeVFSResult result, + PermissionsChangeRequest *request); static void value_field_update (FMPropertiesWindow *window, GtkLabel *field); static void properties_window_update (FMPropertiesWindow *window, GList *files); +static gboolean file_list_at_least_one_directory (GList *file_list); static void is_directory_ready_callback (NautilusFile *file, gpointer data); static void cancel_group_change_callback (gpointer callback_data); @@ -1167,6 +1190,8 @@ properties_window_update (FMPropertiesWi } if (dirty_target) { + gboolean at_least_one_directory; + for (l = window->details->permission_buttons; l != NULL; l = l->next) { permission_button_update (window, GTK_TOGGLE_BUTTON (l->data)); } @@ -1174,6 +1199,11 @@ properties_window_update (FMPropertiesWi for (l = window->details->value_fields; l != NULL; l = l->next) { value_field_update (window, GTK_LABEL (l->data)); } + + at_least_one_directory = file_list_at_least_one_directory (window->details->target_files); + + gtk_widget_set_sensitive (window->details->apply_recursively_button, at_least_one_directory); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (window->details->apply_recursively_button), FALSE); } mime_list = get_mime_list (window); @@ -1311,6 +1341,20 @@ file_list_all_directories (GList *file_l return TRUE; } +static gboolean +file_list_at_least_one_directory (GList *file_list) +{ + GList *l; + + for (l = file_list; l != NULL; l = l->next) { + if (nautilus_file_is_directory (NAUTILUS_FILE (l->data))) { + return TRUE; + } + } + + return FALSE; +} + static void value_field_update_internal (GtkLabel *label, GList *file_list, @@ -2484,23 +2528,119 @@ create_emblems_page (FMPropertiesWindow } static void -permission_change_callback (NautilusFile *file, GnomeVFSResult result, gpointer callback_data) +directory_contents_ready (NautilusDirectory *directory, + GList *files, + PermissionsChangeRequest *request) { - FMPropertiesWindow *window; - g_assert (callback_data != NULL); + NautilusFile *file; + GList *l; - window = FM_PROPERTIES_WINDOW (callback_data); - if (GTK_WIDGET (window)->window != NULL && - window->details->long_operation_underway == 1) { + g_assert (FM_IS_PROPERTIES_WINDOW (request->window)); + + for (l = files; l != NULL; l = l->next) { + file = NAUTILUS_FILE (l->data); + + request->ref++; + request->window->details->long_operation_underway++; + + if (nautilus_file_can_set_permissions (file) && + (((request->scope & PERMISSIONS_CHANGE_SCOPE_FILES) != 0 && + !nautilus_file_is_directory (file)) || + ((request->scope & PERMISSIONS_CHANGE_SCOPE_SUBFOLDERS) != 0 && + nautilus_file_is_directory (file)))) { + GnomeVFSFilePermissions permissions; + + permissions = nautilus_file_get_permissions (file); + if (request->is_on) { + permissions |= request->permission_mask; + } else { + permissions &= ~request->permission_mask; + } + + nautilus_file_set_permissions + (file, permissions, + (NautilusFileOperationCallback) permission_change_callback, + request); + } + } + + + nautilus_directory_file_monitor_remove (directory, request->window); + nautilus_directory_unref (directory); + + if (GTK_WIDGET (request->window)->window != NULL && + request->window->details->long_operation_underway == 1) { + /* finished !! */ + gdk_window_set_cursor (GTK_WIDGET (request->window)->window, NULL); + } + + request->window->details->long_operation_underway--; + + if (--request->ref == 0) { + g_object_unref (request->window); + g_free (request); + } +} + +static void +directory_done_loading (NautilusDirectory *directory, + PermissionsChangeRequest *request) +{ + g_assert (NAUTILUS_IS_DIRECTORY (directory)); + g_assert (FM_IS_PROPERTIES_WINDOW (request->window)); + + nautilus_directory_call_when_ready (directory, + nautilus_mime_actions_get_minimum_file_attributes (), + TRUE, + (NautilusDirectoryCallback) directory_contents_ready, + request); +} + +static void +permission_change_callback (NautilusFile *file, + GnomeVFSResult result, + PermissionsChangeRequest *request) +{ + NautilusDirectory *directory; + + g_assert (NAUTILUS_IS_FILE (file)); + g_assert (FM_IS_PROPERTIES_WINDOW (request->window)); + + if (request->scope != 0 && + nautilus_file_is_directory (file)) { + /* will be dec. in directory_contents_ready */ + request->ref++; + request->window->details->long_operation_underway++; + + directory = nautilus_directory_get_for_file (file); + if (nautilus_directory_are_all_files_seen (directory)) { + directory_done_loading (directory, request); + } else { + g_signal_connect (directory, "done-loading", + G_CALLBACK (directory_done_loading), + request); + nautilus_directory_file_monitor_add (directory, request->window, + TRUE, TRUE, + NAUTILUS_FILE_ATTRIBUTE_CAPABILITIES | + NAUTILUS_FILE_ATTRIBUTE_IS_DIRECTORY, + NULL, NULL); + } + } + + if (GTK_WIDGET (request->window)->window != NULL && + request->window->details->long_operation_underway == 1) { /* finished !! */ - gdk_window_set_cursor (GTK_WIDGET (window)->window, NULL); + gdk_window_set_cursor (GTK_WIDGET (request->window)->window, NULL); } - window->details->long_operation_underway--; + request->window->details->long_operation_underway--; /* Report the error if it's an error. */ fm_report_error_setting_permissions (file, result, NULL); - g_object_unref (window); + if (--request->ref == 0) { + g_object_unref (request->window); + g_free (request); + } } static void @@ -2528,6 +2668,30 @@ get_initial_permission_state (FMProperti } } +static PermissionsChangeScope +get_permissions_change_scope (FMPropertiesWindow *window) +{ + if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (window->details->apply_recursively_button))) { + /* cf. append_recursive_buttons */ + switch (gtk_combo_box_get_active (GTK_COMBO_BOX (window->details->apply_to_combo))) { + case 0: + return PERMISSIONS_CHANGE_SCOPE_FILES; + + case 1: + return PERMISSIONS_CHANGE_SCOPE_SUBFOLDERS; + + case 2: + return PERMISSIONS_CHANGE_SCOPE_FILES | + PERMISSIONS_CHANGE_SCOPE_SUBFOLDERS; + + default: + g_assert_not_reached (); + } + } + + return 0; +} + static void permission_button_toggled (GtkToggleButton *button, FMPropertiesWindow *window) @@ -2536,6 +2700,7 @@ permission_button_toggled (GtkToggleButt GnomeVFSFilePermissions permission_mask; GList *files_on; GList *files_off; + PermissionsChangeScope scope; permission_mask = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (button), "permission")); @@ -2586,6 +2751,11 @@ permission_button_toggled (GtkToggleButt window->details->long_operation_underway += g_list_length (files_on); window->details->long_operation_underway += g_list_length (files_off); + scope = 0; + if (file_list_at_least_one_directory (window->details->target_files)) { + scope = get_permissions_change_scope (window); + } + for (l = files_on; l != NULL; l = l->next) { NautilusFile *file; @@ -2593,15 +2763,22 @@ permission_button_toggled (GtkToggleButt if (nautilus_file_can_set_permissions (file)) { GnomeVFSFilePermissions permissions; + PermissionsChangeRequest *request; permissions = nautilus_file_get_permissions (file); permissions |= permission_mask; - - g_object_ref (window); + + request = g_new (PermissionsChangeRequest, 1); + request->window = g_object_ref (window); + request->scope = scope; + request->is_on = TRUE; + request->permission_mask = permission_mask; + request->ref = 1; + nautilus_file_set_permissions (file, permissions, - permission_change_callback, - window); + (NautilusFileOperationCallback) permission_change_callback, + request); } } @@ -2613,15 +2790,22 @@ permission_button_toggled (GtkToggleButt if (nautilus_file_can_set_permissions (file)) { GnomeVFSFilePermissions permissions; + PermissionsChangeRequest *request; permissions = nautilus_file_get_permissions (file); permissions &= ~permission_mask; - g_object_ref (window); + request = g_new (PermissionsChangeRequest, 1); + request->window = g_object_ref (window); + request->scope = scope; + request->is_on = FALSE; + request->permission_mask = permission_mask; + request->ref = 1; + nautilus_file_set_permissions (file, permissions, - permission_change_callback, - window); + (NautilusFileOperationCallback) permission_change_callback, + request); } } @@ -2826,6 +3010,56 @@ append_special_execution_flags (FMProper } +static void +apply_recursively_button_toggled (GtkToggleButton *button, + GtkWidget *combo) +{ + gboolean sensitive; + + sensitive = GTK_WIDGET_IS_SENSITIVE (GTK_WIDGET (button)) && + gtk_toggle_button_get_active (button); + + gtk_widget_set_sensitive (combo, sensitive); + if (sensitive) { + gtk_widget_grab_focus (combo); + } +} + +static void +append_recursive_buttons (FMPropertiesWindow *window, + GtkTable *table) +{ + unsigned int last_row; + GtkWidget *hbox; + + last_row = append_row (table); + + hbox = gtk_hbox_new (FALSE, 12); + gtk_widget_show (hbox); + gtk_table_attach (table, hbox, + TITLE_COLUMN, VALUE_COLUMN + 1, + last_row, last_row + 1, + GTK_FILL, 0, + 0, 0); + + window->details->apply_recursively_button = + gtk_check_button_new_with_mnemonic ("_Apply recursively:"); + gtk_widget_show (window->details->apply_recursively_button); + gtk_container_add (GTK_CONTAINER (hbox), window->details->apply_recursively_button); + + window->details->apply_to_combo = gtk_combo_box_new_text (); + gtk_combo_box_append_text (GTK_COMBO_BOX (window->details->apply_to_combo), _("Files")); + gtk_combo_box_append_text (GTK_COMBO_BOX (window->details->apply_to_combo), _("Folders")); + gtk_combo_box_append_text (GTK_COMBO_BOX (window->details->apply_to_combo), _("Whole Contents")); + gtk_combo_box_set_active (GTK_COMBO_BOX (window->details->apply_to_combo), 2); + gtk_widget_show (window->details->apply_to_combo); + gtk_box_pack_start (GTK_BOX (hbox), window->details->apply_to_combo, FALSE, FALSE, 0); + + g_signal_connect (window->details->apply_recursively_button, "toggled", + G_CALLBACK (apply_recursively_button_toggled), + window->details->apply_to_combo); +} + static gboolean all_can_get_permissions (GList *file_list) { @@ -3060,6 +3294,10 @@ create_permissions_page (FMPropertiesWin (window, page_table, _("Last changed:"), "date_permissions", _("--"), FALSE); + + append_separator (page_table); + + append_recursive_buttons (window, page_table); } else { if (!is_multi_file_window (window)) { file_name = nautilus_file_get_display_name (get_target_file (window));
Attachment:
signature.asc
Description: Dies ist ein digital signierter Nachrichtenteil