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	28 Dec 2005 23:52:02 -0000
@@ -26,6 +26,7 @@
 #include "fm-properties-window.h"
 
 #include "fm-error-reporting.h"
+#include <glib/gi18n.h>
 #include <eel/eel-accessibility.h>
 #include <eel/eel-ellipsizing-label.h>
 #include <eel/eel-gdk-pixbuf-extensions.h>
@@ -59,7 +60,6 @@
 #include <gtk/gtkvbox.h>
 #include <gtk/gtktreemodel.h>
 #include <gtk/gtkliststore.h>
-#include <libgnome/gnome-i18n.h>
 #include <libgnome/gnome-macros.h>
 #include <libgnomeui/gnome-dialog.h>
 #include <libgnomeui/gnome-help.h>
@@ -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>
@@ -109,16 +111,19 @@ struct FMPropertiesWindowDetails {	
 	guint update_directory_contents_timeout_id;
 	guint update_files_timeout_id;
 
-	GList *special_flags_widgets;
-	int first_special_flags_row;
-	int num_special_flags_rows;
-
 	GList *emblem_buttons;
 	GHashTable *initial_emblems;
 
-	GList *permission_buttons;
+	GList *permission_combo_boxes;
 	GHashTable *initial_permissions;
 
+	GtkDialog *permission_details_dialog;
+
+	GList *scheduled_file_permission_changes_on;
+	GList *scheduled_file_permission_changes_off;
+	GList *scheduled_folder_permission_changes_on;
+	GList *scheduled_folder_permission_changes_off;
+
 	GList *value_fields;
 
 	GList *mime_list;
@@ -175,6 +180,19 @@ static const GtkTargetEntry target_table
 	{ "x-special/gnome-reset-background", 0, TARGET_RESET_BACKGROUND }
 };
 
+typedef struct {
+	FMPropertiesWindow *window;
+
+	GnomeVFSFilePermissions file_on_mask;
+	GnomeVFSFilePermissions file_off_mask;
+	GnomeVFSFilePermissions folder_on_mask;
+	GnomeVFSFilePermissions folder_off_mask;
+
+	gboolean is_recursive;
+
+	unsigned int ref;
+} PermissionsChangeRequest;
+
 #define DIRECTORY_CONTENTS_UPDATE_INTERVAL	200 /* milliseconds */
 #define FILES_UPDATE_INTERVAL			200 /* milliseconds */
 #define STANDARD_EMBLEM_HEIGHT			52
@@ -183,12 +201,20 @@ static const GtkTargetEntry target_table
 static void directory_contents_value_field_update (FMPropertiesWindow *window);
 static void file_changed_callback                 (NautilusFile       *file,
 						   gpointer            user_data);
+static void permission_combo_box_update           (FMPropertiesWindow *window,
+						   GtkComboBox        *combo);
 static void permission_button_update              (FMPropertiesWindow *window,
 						   GtkToggleButton    *button);
+static void permission_details_dialog_update      (GtkDialog          *dialog);
+static void apply_scheduled_permission_changes    (FMPropertiesWindow *window,
+						   gboolean            is_recursive);
 static void value_field_update                    (FMPropertiesWindow *window,
 						   GtkLabel           *field);
 static void properties_window_update              (FMPropertiesWindow *window,
 						   GList              *files);
+static void permission_change_callback            (NautilusFile       *file,
+						   GnomeVFSResult      result,
+						   PermissionsChangeRequest *request);
 static void is_directory_ready_callback           (NautilusFile       *file,
 						   gpointer            data);
 static void cancel_group_change_callback          (gpointer            callback_data);
@@ -338,6 +364,7 @@ add_prompt (GtkVBox *vbox, const char *p
 	}
 }
 
+/*
 static void
 add_prompt_and_separator (GtkVBox *vbox, const char *prompt_text)
 {
@@ -348,7 +375,7 @@ add_prompt_and_separator (GtkVBox *vbox,
  	separator_line = gtk_hseparator_new ();
   	gtk_widget_show (separator_line);
   	gtk_box_pack_end (GTK_BOX (vbox), separator_line, TRUE, TRUE, GNOME_PAD_BIG);
-}
+}*/
 
 static GdkPixbuf *
 get_pixbuf_for_properties_window (FMPropertiesWindow *window)
@@ -1167,10 +1194,14 @@ properties_window_update (FMPropertiesWi
 	}
 
 	if (dirty_target) {
-		for (l = window->details->permission_buttons; l != NULL; l = l->next) {
-			permission_button_update (window, GTK_TOGGLE_BUTTON (l->data));
+		if (window->details->permission_details_dialog != NULL) {
+			permission_details_dialog_update (window->details->permission_details_dialog);
 		}
-		
+
+		for (l = window->details->permission_combo_boxes; l != NULL; l = l->next) {
+			permission_combo_box_update (window, GTK_COMBO_BOX (l->data));
+		}
+
 		for (l = window->details->value_fields; l != NULL; l = l->next) {
 			value_field_update (window, GTK_LABEL (l->data));
 		}
@@ -1300,15 +1331,64 @@ file_list_all_local (GList *file_list)
 }
 
 static gboolean
-file_list_all_directories (GList *file_list)
+file_list_all_directories (GList *file_list,
+			   gboolean *one_ret)
+{
+	GList *l;
+	gboolean all, one;
+
+	all = file_list != NULL;
+	one = FALSE;
+
+	for (l = file_list; l != NULL; l = l->next) {
+		gboolean is_directory;
+
+		is_directory = nautilus_file_is_directory (NAUTILUS_FILE (l->data));
+
+		all &= is_directory;
+		one |= is_directory;
+
+		if (!all && one) {
+			break;
+		}
+	}
+
+	if (one_ret) {
+		*one_ret = one;
+	}
+
+	return all;
+}
+
+
+static gboolean
+file_list_same_permissions (GList *file_list,
+			    GnomeVFSFilePermissions perm_mask)
 {
+	NautilusFile *file;
+	GnomeVFSFilePermissions perms, last_perms;
 	GList *l;
+
+	last_perms = 0;
+
 	for (l = file_list; l != NULL; l = l->next) {
-		if (!nautilus_file_is_directory (NAUTILUS_FILE (l->data))) {
+		file = NAUTILUS_FILE (l->data);
+
+		if (!nautilus_file_can_get_permissions (file)) {
 			return FALSE;
 		}
+
+		perms = nautilus_file_get_permissions (file);
+		perms &= perm_mask;
+
+		if (l != file_list && perms != last_perms) {
+			return FALSE;
+		}
+
+		last_perms = perms;
 	}
-	return TRUE;
+
+	return l != file_list;
 }
 
 static void
@@ -1415,6 +1495,15 @@ attach_ellipsizing_value_label (GtkTable
 }
 
 static void
+value_field_destroy (GtkLabel *value_field,
+		     FMPropertiesWindow *window)
+{
+	g_assert (FM_IS_PROPERTIES_WINDOW (window));
+
+	window->details->value_fields = g_list_remove (window->details->value_fields, value_field);
+}
+
+static void
 attach_value_field_internal (FMPropertiesWindow *window,
 			     GtkTable *table,
 			     int row,
@@ -1422,7 +1511,8 @@ attach_value_field_internal (FMPropertie
 			     const char *file_attribute_name,
 			     const char *inconsistent_string,
 			     gboolean show_original,
-			     gboolean ellipsize_text)
+			     gboolean ellipsize_text,
+			     gboolean update_now)
 {
 	GtkLabel *value_field;
 
@@ -1442,8 +1532,16 @@ attach_value_field_internal (FMPropertie
 	g_object_set_data (G_OBJECT (value_field), "show_original", GINT_TO_POINTER (show_original));
 	g_object_set_data (G_OBJECT (value_field), "ellipsize_text", GINT_TO_POINTER (ellipsize_text));
 
+	g_signal_connect (G_OBJECT (value_field), "destroy",
+			  G_CALLBACK (value_field_destroy),
+			  window);
+
 	window->details->value_fields = g_list_prepend (window->details->value_fields,
 							value_field);
+
+	if (update_now) {
+		value_field_update (window, value_field);
+	}
 }			     
 
 static void
@@ -1453,14 +1551,16 @@ attach_value_field (FMPropertiesWindow *
 		    int column,
 		    const char *file_attribute_name,
 		    const char *inconsistent_string,
-		    gboolean show_original)
+		    gboolean show_original,
+		    gboolean update_now)
 {
 	attach_value_field_internal (window, 
 				     table, row, column, 
 				     file_attribute_name, 
 				     inconsistent_string,
 				     show_original,
-				     FALSE);
+				     FALSE,
+				     update_now);
 }
 
 static void
@@ -1470,14 +1570,16 @@ attach_ellipsizing_value_field (FMProper
 		    		int column,
 		    		const char *file_attribute_name,
 				const char *inconsistent_string,
-				gboolean show_original)
+				gboolean show_original,
+				gboolean update_now)
 {
 	attach_value_field_internal (window,
 				     table, row, column, 
 				     file_attribute_name, 
 				     inconsistent_string, 
 				     show_original,
-				     TRUE);
+				     TRUE,
+				     update_now);
 }
 
 static void
@@ -1622,10 +1724,10 @@ attach_combo_box (GtkTable *table,
 					      NULL,
 					      NULL);
 
-	/* Put combo box in alignment to make it left-justified
+	/* Put combo box in alignment to make it right-justified
 	 * but minimally sized.
 	 */	
-	aligner = gtk_alignment_new (0, 0.5, 0, 0);
+	aligner = gtk_alignment_new (1.0, 0.5, 0, 0);
 	gtk_widget_show (aligner);
 
 	gtk_container_add (GTK_CONTAINER (aligner), combo_box);
@@ -2045,7 +2147,8 @@ append_title_value_pair (FMPropertiesWin
 			 const char *title, 
  			 const char *file_attribute_name,
 			 const char *inconsistent_state,
-			 gboolean show_original)
+			 gboolean show_original,
+			 gboolean update_now)
 {
 	guint last_row;
 
@@ -2053,7 +2156,8 @@ append_title_value_pair (FMPropertiesWin
 	attach_value_field (window, table, last_row, VALUE_COLUMN, 
 			    file_attribute_name,
 			    inconsistent_state,
-			    show_original); 
+			    show_original,
+			    update_now); 
 
 	return last_row;
 }
@@ -2064,7 +2168,8 @@ append_title_and_ellipsizing_value (FMPr
 				    const char *title,
 				    const char *file_attribute_name,
 				    const char *inconsistent_state,
-				    gboolean show_original)
+				    gboolean show_original,
+				    gboolean update_now)
 {
 	guint last_row;
 
@@ -2072,34 +2177,12 @@ append_title_and_ellipsizing_value (FMPr
 	attach_ellipsizing_value_field (window, table, last_row, VALUE_COLUMN, 
 					file_attribute_name,
 					inconsistent_state,
-					show_original);
+					show_original,
+					update_now);
 
 	return last_row;
 }
 
-static void
-update_visibility_of_table_rows (GtkTable *table,
-		   	 	 gboolean should_show,
-		   		 int first_row, 
-		   		 int row_count,
-		   		 GList *widgets)
-{
-	GList *node;
-	int i;
-
-	for (node = widgets; node != NULL; node = node->next) {
-		if (should_show) {
-			gtk_widget_show (GTK_WIDGET (node->data));
-		} else {
-			gtk_widget_hide (GTK_WIDGET (node->data));
-		}
-	}
-
-	for (i= 0; i < row_count; ++i) {
-		gtk_table_set_row_spacing (table, first_row + i, should_show ? GNOME_PAD : 0);
-	}
-}				   
-
 static guint
 append_directory_contents_fields (FMPropertiesWindow *window,
 				  GtkTable *table)
@@ -2227,7 +2310,7 @@ should_show_accessed_date (FMPropertiesW
 	 * day decide that it is useful, we should separately
 	 * consider whether it's useful for "trash:".
 	 */
-	if (file_list_all_directories (window->details->target_files)) {
+	if (file_list_all_directories (window->details->target_files, NULL)) {
 		return FALSE;
 	}
 
@@ -2237,7 +2320,7 @@ should_show_accessed_date (FMPropertiesW
 static gboolean
 should_show_mime_type (FMPropertiesWindow *window) 
 {
-	if (file_list_all_directories (window->details->target_files)) {
+	if (file_list_all_directories (window->details->target_files, NULL)) {
 		return FALSE;
 	}
 
@@ -2259,7 +2342,7 @@ static gboolean
 should_show_free_space (FMPropertiesWindow *window)
 {
 	if (file_list_all_local (window->details->target_files)
-	    && file_list_all_directories (window->details->target_files)) {
+	    && file_list_all_directories (window->details->target_files, NULL)) {
 		return TRUE;
 	}
 
@@ -2329,6 +2412,7 @@ create_basic_page (FMPropertiesWindow *w
 					 table, _("Type:"), 
 					 "type",
 					 _("--"),
+					 FALSE,
 					 FALSE);
 	}
 
@@ -2339,23 +2423,27 @@ create_basic_page (FMPropertiesWindow *w
 		append_title_value_pair (window, table, _("Size:"), 
 					 "size",
 					 _("--"),
+					 FALSE,
 					 FALSE);
 	}
 
 	append_title_and_ellipsizing_value (window, table, _("Location:"), 
 					    "where",
 					    _("--"),
-					    TRUE);
+					    TRUE,
+					    FALSE);
 	
 	if (should_show_free_space (window)) {
 		append_title_and_ellipsizing_value (window, table, 
 						    _("Volume:"), 
 						    "volume",
 						    _("--"),
+						    FALSE,
 						    FALSE);
 		append_title_value_pair (window, table, _("Free space:"), 
 					 "free_space",
 					 _("--"),
+					 FALSE,
 					 FALSE);
 	}
 
@@ -2364,12 +2452,14 @@ create_basic_page (FMPropertiesWindow *w
 						    _("Link target:"), 
 						    "link_target",
 						    _("--"),
+						    FALSE,
 						    FALSE);
 	}
 	if (should_show_mime_type (window)) {
 		append_title_value_pair (window, table, _("MIME type:"), 
 					 "mime_type",
 					 _("--"),
+					 FALSE,
 					 FALSE);
 	}				  
 	
@@ -2379,12 +2469,14 @@ create_basic_page (FMPropertiesWindow *w
 	append_title_value_pair (window, table, _("Modified:"), 
 				 "date_modified",
 				 _("--"),
+				 FALSE,
 				 FALSE);
 	
 	if (should_show_accessed_date (window)) {
 		append_title_value_pair (window, table, _("Accessed:"), 
 					 "date_accessed",
 					 _("--"),
+					 FALSE,
 					 FALSE);
 	}
 }
@@ -2484,26 +2576,135 @@ 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;
+ 
+	g_assert (FM_IS_PROPERTIES_WINDOW (request->window));
+
+	window = request->window;
+
+	for (l = files; l != NULL; l = l->next) {
+		file = NAUTILUS_FILE (l->data);
+
+		request->ref++;
+		window->details->long_operation_underway++;
+
+		if (nautilus_file_can_set_permissions (file)) {
+			GnomeVFSFilePermissions permissions;
+
+			permissions = nautilus_file_get_permissions (file);
+
+			/* FIXME we might be able to save I/O if we
+			 * directly call permission_change_callback
+			 * for files that weren't modified due to
+			 * our request */
+
+			if (nautilus_file_is_directory (file)) {
+				permissions |= request->folder_on_mask;
+				permissions &= ~request->folder_off_mask;
+			} else {
+				permissions |= request->file_on_mask;
+				permissions &= ~request->file_off_mask;
+			}
+
+			nautilus_file_set_permissions
+				(file, permissions,
+				 (NautilusFileOperationCallback) permission_change_callback,
+				 request);
+		}
+	}
+
+
+	nautilus_directory_file_monitor_remove (directory, window);
+	nautilus_directory_unref (directory);
 
-	window = FM_PROPERTIES_WINDOW (callback_data);
 	if (GTK_WIDGET (window)->window != NULL &&
 	    window->details->long_operation_underway == 1) {
 		/* finished !! */
 		gdk_window_set_cursor (GTK_WIDGET (window)->window, NULL);
+
+		if (window->details->permission_details_dialog != NULL &&
+		    GTK_WIDGET (window->details->permission_details_dialog)->window != NULL) {
+			gdk_window_set_cursor (GTK_WIDGET (window->details->permission_details_dialog)->window, NULL);
+		}
 	}
+
 	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 (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->is_recursive &&
+	    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 (request->window)->window, NULL);
+	}
+	request->window->details->long_operation_underway--;
+
+ 	/* Report the error if it's an error. */
+ 	fm_report_error_setting_permissions (file, result, NULL);
+ 
+	if (--request->ref == 0) {
+		g_object_unref (request->window);
+		g_free (request);
+	}
+}
+ 
+#if 0
+static void
 get_initial_permission_state (FMPropertiesWindow *window,
 			      GnomeVFSFilePermissions mask,
 			      GList **on,
@@ -2527,7 +2728,208 @@ get_initial_permission_state (FMProperti
 		}
 	}
 }
+#endif
+
+static GList **
+get_scheduled_permission_list (FMPropertiesWindow *window,
+			       gboolean is_folder,
+			       gboolean is_on)
+{
+	if (is_folder && is_on) {
+		return &window->details->scheduled_folder_permission_changes_on;
+	} else if (is_folder) {
+		return &window->details->scheduled_folder_permission_changes_off;
+	} else if (is_on) {
+		return &window->details->scheduled_file_permission_changes_on;
+	} else {
+		return &window->details->scheduled_file_permission_changes_off;
+	}
+}
+
+static void
+schedule_permission_change (FMPropertiesWindow *window,
+			    GnomeVFSFilePermissions mask,
+			    gboolean is_folder,
+			    gboolean is_on)
+{
+	GList **list;
+
+	list = get_scheduled_permission_list (window, is_folder, is_on);
+	*list = g_list_append (*list, GUINT_TO_POINTER (mask));
+}
+
+static void
+unschedule_permission_change (FMPropertiesWindow *window,
+			      GnomeVFSFilePermissions mask,
+			      gboolean is_folder,
+			      gboolean is_on)
+{
+	GList **list;
+
+	list = get_scheduled_permission_list (window, is_folder, is_on);
+	*list = g_list_remove (*list, GUINT_TO_POINTER (mask));
+}
+
+static void
+unschedule_permission_changes (FMPropertiesWindow *window)
+{
+	g_list_free (window->details->scheduled_folder_permission_changes_on);
+	window->details->scheduled_folder_permission_changes_on = NULL;
+
+	g_list_free (window->details->scheduled_folder_permission_changes_off);
+	window->details->scheduled_folder_permission_changes_off = NULL;
+
+	g_list_free (window->details->scheduled_file_permission_changes_on);
+	window->details->scheduled_file_permission_changes_on = NULL;
+
+	g_list_free (window->details->scheduled_file_permission_changes_off);
+	window->details->scheduled_file_permission_changes_off = NULL;
+}
+
+static void
+apply_scheduled_permission_changes (FMPropertiesWindow *window,
+				    gboolean is_recursive)
+{
+	PermissionsChangeRequest *request;
+	GList *perms;
+	GList *l;
+
+	g_assert (FM_IS_PROPERTIES_WINDOW (window));
+
+	request = g_new0 (PermissionsChangeRequest, 1);
+	request->window = g_object_ref (window);
+	request->ref = 1;
+
+	perms = *get_scheduled_permission_list (window, FALSE, TRUE);
+	for (l = perms; l != NULL; l = l->next) {
+		request->file_on_mask |= GPOINTER_TO_UINT (l->data);
+	}
+
+	perms = *get_scheduled_permission_list (window, FALSE, FALSE);
+	for (l = perms; l != NULL; l = l->next) {
+		request->file_off_mask |= GPOINTER_TO_UINT (l->data);
+	}
+
+	perms = *get_scheduled_permission_list (window, TRUE, TRUE);
+	for (l = perms; l != NULL; l = l->next) {
+		request->folder_on_mask |= GPOINTER_TO_UINT (l->data);
+	}
+
+	perms = *get_scheduled_permission_list (window, TRUE, FALSE);
+	for (l = perms; l != NULL; l = l->next) {
+		request->folder_off_mask |= GPOINTER_TO_UINT (l->data);
+	}
+
+	request->is_recursive = is_recursive;
+
+	if (window->details->long_operation_underway == 0) {
+		/* start long operation */
+		GdkCursor *cursor;
+
+		cursor = gdk_cursor_new (GDK_WATCH);
+
+		gdk_window_set_cursor (GTK_WIDGET (window)->window, cursor);
+
+		if (window->details->permission_details_dialog != NULL &&
+		    GTK_WIDGET (window->details->permission_details_dialog)->window != NULL) {
+			gdk_window_set_cursor (GTK_WIDGET (window->details->permission_details_dialog)->window, cursor);
+		}
+
+		gdk_cursor_unref (cursor);
+	}
+
+	for (l = window->details->target_files; l != NULL; l = l->next) {
+		NautilusFile *file;
+
+		file = NAUTILUS_FILE (l->data);
+
+		if (nautilus_file_can_set_permissions (file)) {
+			GnomeVFSFilePermissions permissions;
+
+			request->ref++;
+			window->details->long_operation_underway++;
+
+			permissions = nautilus_file_get_permissions (file);
+
+			if (nautilus_file_is_directory (file)) {
+				permissions |= request->folder_on_mask;
+				permissions &= ~request->folder_off_mask;
+			} else {
+				permissions |= request->file_on_mask;
+				permissions &= ~request->file_off_mask;
+			}
+
+			nautilus_file_set_permissions
+				(file, permissions,
+				 (NautilusFileOperationCallback) permission_change_callback,
+				 request);
+		}
+	}
+
+	if (--request->ref == 0) {
+		g_object_unref (window);
+		g_free (request);
+	}
+}
+
+
+static void
+eel_gtk_label_make_italic (GtkLabel *label)
+{
+	PangoFontDescription *font_desc;
+
+	g_return_if_fail (GTK_IS_LABEL (label));
+
+	font_desc = pango_font_description_new ();
+
+	pango_font_description_set_style (font_desc,
+					  PANGO_STYLE_ITALIC);
+	gtk_widget_modify_font (GTK_WIDGET (label), font_desc);
+
+	pango_font_description_free (font_desc);
+}
+
+static void
+eel_gtk_label_make_normal (GtkLabel *label)
+{
+	PangoFontDescription *font_desc;
+
+	g_return_if_fail (GTK_IS_LABEL (label));
+
+	font_desc = pango_font_description_new ();
+
+	pango_font_description_set_style (font_desc,
+					  PANGO_STYLE_NORMAL);
+	gtk_widget_modify_font (GTK_WIDGET (label), font_desc);
+
+	pango_font_description_free (font_desc);
+}
+
+static void
+permission_button_toggled (GtkToggleButton *button, 
+			   FMPropertiesWindow *window)
+{
+	GnomeVFSFilePermissions permission_mask;
+	gboolean is_folder;
+
+	permission_mask = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (button),
+							      "permission"));
+
+	is_folder = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (button),
+							 "is_folder"));
+
+	unschedule_permission_change (window, permission_mask, is_folder,
+				      !gtk_toggle_button_get_active (button));
+	schedule_permission_change (window, permission_mask, is_folder,
+				    gtk_toggle_button_get_active (button));
+
+	eel_gtk_label_make_italic (GTK_LABEL (GTK_BIN (button)->child));
+
+	gtk_dialog_set_response_sensitive (GTK_DIALOG (window->details->permission_details_dialog),
+					   GTK_RESPONSE_OK, TRUE);
+}
 
+#if 0
 static void
 permission_button_toggled (GtkToggleButton *button, 
 			   FMPropertiesWindow *window)
@@ -2536,10 +2938,19 @@ permission_button_toggled (GtkToggleButt
 	GnomeVFSFilePermissions permission_mask;
 	GList *files_on;
 	GList *files_off;
+	gboolean is_folder;
 	
 	permission_mask = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (button),
 							      "permission"));
 
+	is_folder = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (button),
+							 "is_folder"));
+
+	unschedule_permission_change (window, permission_mask, is_folder,
+				      !gtk_toggle_button_get_active (button));
+	schedule_permission_change (window, permission_mask, is_folder,
+				    gtk_toggle_button_get_active (button));
+
 	files_on = NULL;
 	files_off = NULL;
 	if (gtk_toggle_button_get_active (button)
@@ -2600,7 +3011,7 @@ permission_button_toggled (GtkToggleButt
 			g_object_ref (window);
 			nautilus_file_set_permissions
 				(file, permissions,
-				 permission_change_callback,
+				 (NautilusFileOperationCallback) permission_change_callback,
 				 window);
 		}
 		
@@ -2620,7 +3031,7 @@ permission_button_toggled (GtkToggleButt
 			g_object_ref (window);
 			nautilus_file_set_permissions
 				(file, permissions,
-				 permission_change_callback,
+				 (NautilusFileOperationCallback) permission_change_callback,
 				 window);
 		}
 	}	
@@ -2628,6 +3039,7 @@ permission_button_toggled (GtkToggleButt
 	g_list_free (files_on);
 	g_list_free (files_off);
 }
+#endif
 
 static void
 permission_button_update (FMPropertiesWindow *window,
@@ -2637,11 +3049,21 @@ permission_button_update (FMPropertiesWi
 	gboolean all_set;
 	gboolean all_unset;
 	gboolean all_cannot_set;
+	gboolean is_folder;
 	GnomeVFSFilePermissions button_permission;
 	
 	button_permission = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (button),
 								"permission"));
-	
+	is_folder = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (button),
+							 "is_folder"));
+
+	if (!is_folder && file_list_all_directories (window->details->target_files, NULL)) {
+		all_cannot_set = FALSE;
+		all_set = FALSE;
+		all_unset = TRUE;
+		goto set;
+	}
+
 	all_set = TRUE;
 	all_unset = TRUE;
 	all_cannot_set = TRUE;
@@ -2657,7 +3079,7 @@ permission_button_update (FMPropertiesWi
 
 		file_permissions = nautilus_file_get_permissions (file);
 
-		if ((file_permissions & button_permission) != 0) {
+		if ((file_permissions & button_permission) == button_permission) {
 			all_unset = FALSE;
 		} else {
 			all_set = FALSE;
@@ -2667,7 +3089,8 @@ permission_button_update (FMPropertiesWi
 			all_cannot_set = FALSE;
 		}
 	}
-	
+
+set:
 	g_signal_handlers_block_by_func (G_OBJECT (button), 
 					 G_CALLBACK (permission_button_toggled),
 					 window);
@@ -2681,21 +3104,20 @@ permission_button_update (FMPropertiesWi
 					   window);
 }
 
-
 static void
 set_up_permissions_checkbox (FMPropertiesWindow *window,
 			     GtkWidget *check_button, 
-			     GnomeVFSFilePermissions permission)
+			     GnomeVFSFilePermissions permission,
+			     GList **button_list,
+			     gboolean is_folder)
 {
 	/* Load up the check_button with data we'll need when updating its state. */
         g_object_set_data (G_OBJECT (check_button), "permission", 
 			   GINT_TO_POINTER (permission));
-        g_object_set_data (G_OBJECT (check_button), "properties_window", 
-			   window);
-	
-	window->details->permission_buttons = 
-		g_list_prepend (window->details->permission_buttons,
-				check_button);
+        g_object_set_data (G_OBJECT (check_button), "is_folder", 
+			   GINT_TO_POINTER (is_folder));
+
+	*button_list = g_list_prepend (*button_list, check_button);
 
 	g_signal_connect_object (check_button, "toggled",
 				 G_CALLBACK (permission_button_toggled),
@@ -2708,13 +3130,18 @@ add_permissions_checkbox (FMPropertiesWi
 			  GtkTable *table, 
 			  int row, int column, 
 			  GnomeVFSFilePermissions permission_to_check,
-			  GtkLabel *label_for)
+			  const char *optional_label,
+			  GtkLabel *label_for,
+			  GList **button_list,
+			  gboolean is_folder)
 {
 	GtkWidget *check_button;
-	gchar *label;
 	gboolean a11y_enabled;
+	const char *label;
 
-	if (column == PERMISSIONS_CHECKBOXES_READ_COLUMN) {
+	if (optional_label != NULL) {
+		label = optional_label;
+	} else if (column == PERMISSIONS_CHECKBOXES_READ_COLUMN) {
 		label = _("_Read");
 	} else if (column == PERMISSIONS_CHECKBOXES_WRITE_COLUMN) {
 		label = _("_Write");
@@ -2732,7 +3159,9 @@ add_permissions_checkbox (FMPropertiesWi
 
 	set_up_permissions_checkbox (window, 
 				     check_button, 
-				     permission_to_check);
+				     permission_to_check,
+				     button_list,
+				     is_folder);
 
 	a11y_enabled = GTK_IS_ACCESSIBLE (gtk_widget_get_accessible (check_button));
 	if (a11y_enabled) {
@@ -2741,89 +3170,319 @@ add_permissions_checkbox (FMPropertiesWi
 	}
 }
 
-static GtkWidget *
-append_special_execution_checkbox (FMPropertiesWindow *window,
-				   GtkTable *table,
-				   const char *label_text,
-				   GnomeVFSFilePermissions permission_to_check)
+typedef enum {
+	SIMPLE_PERMISSIONS_MODE_NONE = 0,
+	SIMPLE_PERMISSIONS_MODE_READ,
+	SIMPLE_PERMISSIONS_MODE_READ_WRITE,
+	SIMPLE_PERMISSIONS_MODE_READ_EXECUTE,
+	SIMPLE_PERMISSIONS_MODE_READ_WRITE_EXECUTE,
+} SimplePermissionsMode;
+
+typedef enum {
+	SIMPLE_PERMISSIONS_SCOPE_USER = 0,
+	SIMPLE_PERMISSIONS_SCOPE_GROUP,
+	SIMPLE_PERMISSIONS_SCOPE_OTHER
+} SimplePermissionScope;
+
+static void
+simple_permission_scope_to_vfs (SimplePermissionScope scope,
+				GnomeVFSFilePermissions *r,
+				GnomeVFSFilePermissions *w,
+				GnomeVFSFilePermissions *x,
+				GnomeVFSFilePermissions *all)
+{
+	switch (scope) {
+	case SIMPLE_PERMISSIONS_SCOPE_USER:
+		*r = GNOME_VFS_PERM_USER_READ;
+		*w = GNOME_VFS_PERM_USER_WRITE;
+		*x = GNOME_VFS_PERM_USER_EXEC;
+		*all = GNOME_VFS_PERM_USER_ALL;
+		break;
+
+	case SIMPLE_PERMISSIONS_SCOPE_GROUP:
+		*r = GNOME_VFS_PERM_GROUP_READ;
+		*w = GNOME_VFS_PERM_GROUP_WRITE;
+		*x = GNOME_VFS_PERM_GROUP_EXEC;
+		*all = GNOME_VFS_PERM_GROUP_ALL;
+		break;
+
+	case SIMPLE_PERMISSIONS_SCOPE_OTHER:
+		*r = GNOME_VFS_PERM_OTHER_READ;
+		*w = GNOME_VFS_PERM_OTHER_WRITE;
+		*x = GNOME_VFS_PERM_OTHER_EXEC;
+		*all = GNOME_VFS_PERM_OTHER_ALL;
+		break;
+
+	default:
+		g_assert_not_reached ();
+	}
+}
+
+static int
+simple_permission_scope_to_combo_box_iter (SimplePermissionScope scope,
+					   gboolean is_folder,
+					   GnomeVFSFilePermissions permissions)
+{
+	GnomeVFSFilePermissions r, w, x, all;
+
+	simple_permission_scope_to_vfs (scope, &r, &w, &x, &all);
+
+	if ((permissions & all) == 0) {
+		return SIMPLE_PERMISSIONS_MODE_NONE;
+	} else if (is_folder) {
+		if ((permissions & all) == (r | x)) {
+			return SIMPLE_PERMISSIONS_MODE_READ;
+		} else if ((permissions & all) == (r | w | x)) {
+			return SIMPLE_PERMISSIONS_MODE_READ_WRITE;
+		}
+	} else {
+		if ((permissions & all) == r) {
+			return SIMPLE_PERMISSIONS_MODE_READ;
+		} else if ((permissions & all) == (r | w)) {
+			return SIMPLE_PERMISSIONS_MODE_READ_WRITE;
+		} else if ((permissions & all) == (r | x)) {
+			return SIMPLE_PERMISSIONS_MODE_READ_EXECUTE;
+		} else if ((permissions & all) == (r | w | x)) {
+			return SIMPLE_PERMISSIONS_MODE_READ_WRITE_EXECUTE;
+		}
+	}
+
+	return -1;
+}
+
+static void
+get_combo_permissions (GtkComboBox *combo,
+		       GnomeVFSFilePermissions *file_on_permissions,
+		       GnomeVFSFilePermissions *file_off_permissions,
+		       GnomeVFSFilePermissions *folder_on_permissions,
+		       GnomeVFSFilePermissions *folder_off_permissions)
 {
-	GtkWidget *check_button;
-	guint last_row;
+	SimplePermissionScope scope;
+	GnomeVFSFilePermissions r, w, x, all;
+	gboolean is_folder;
 
-	last_row = append_row (table);
+	scope = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (combo), "scope"));
 
-	check_button = gtk_check_button_new_with_mnemonic (label_text);
-	gtk_widget_show (check_button);
+	is_folder = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (combo), "is_folder"));
 
-	gtk_table_attach (table, check_button,
-			  VALUE_COLUMN, VALUE_COLUMN + 1,
-			  last_row, last_row + 1,
-			  GTK_FILL, 0,
-			  0, 0);
+	*file_on_permissions = *file_off_permissions = 0;
+	*folder_on_permissions = *folder_off_permissions = 0;
 
-	set_up_permissions_checkbox (window, 
-				     check_button, 
-				     permission_to_check);
-	++window->details->num_special_flags_rows;
+	r = w = x = all = 0;
+
+	simple_permission_scope_to_vfs (scope, &r, &w, &x, &all);
+
+	switch (gtk_combo_box_get_active (combo)) {
+	case SIMPLE_PERMISSIONS_MODE_NONE:
+		*file_on_permissions = 0;
+		*folder_on_permissions = 0;
+		break;
+
+	case SIMPLE_PERMISSIONS_MODE_READ:
+		*file_on_permissions = r;
+		*folder_on_permissions = *file_on_permissions | x;
+		break;
+
+	case SIMPLE_PERMISSIONS_MODE_READ_WRITE:
+		*file_on_permissions = r | w;
+		*folder_on_permissions = *file_on_permissions | x;
+		break;
 
-	return check_button;
+	case SIMPLE_PERMISSIONS_MODE_READ_EXECUTE:
+		*file_on_permissions = r | w | x;
+		*folder_on_permissions = *file_on_permissions;
+		break;
+
+	case SIMPLE_PERMISSIONS_MODE_READ_WRITE_EXECUTE:
+		*file_on_permissions = r | w | x;
+		*folder_on_permissions = *file_on_permissions;
+		break;
+
+	default:
+		g_assert_not_reached ();
+	}
+
+	*folder_off_permissions = all & ~*folder_on_permissions;
+	*file_off_permissions = all & ~*file_on_permissions;
+	if (is_folder) {
+		/* Don't kill x bit of executables when making folder readable */
+		*file_off_permissions &= ~x;
+	}
 }
 
 static void
-remember_special_flags_widget (FMPropertiesWindow *window, GtkWidget *widget)
+permission_combo_box_changed (GtkComboBox *combo,
+			      FMPropertiesWindow *window)
 {
+	GnomeVFSFilePermissions file_on_permissions;
+	GnomeVFSFilePermissions file_off_permissions;
+	GnomeVFSFilePermissions folder_on_permissions;
+	GnomeVFSFilePermissions folder_off_permissions;
+	gboolean recursive;
+
 	g_assert (FM_IS_PROPERTIES_WINDOW (window));
-	g_assert (GTK_IS_WIDGET (widget));
-	
-	window->details->special_flags_widgets = 
-		g_list_prepend (window->details->special_flags_widgets, widget);
+
+	recursive = FALSE;
+
+	if (file_list_all_directories (window->details->target_files, NULL)) {
+		int res;
+
+		res = eel_run_simple_dialog
+			(GTK_WIDGET (window), TRUE,
+			 GTK_MESSAGE_QUESTION,
+			 /* translators: the plural here will be "Folder" */
+			 ngettext ("Apply Changes to Folder Contents?",
+				   "Apply Changes to Folder Contents?",
+				   g_list_length (window->details->target_files)),
+			 ngettext ("You are about to change the access rights to a folder. "
+				   "You can apply these changes to the folder itself only, or to its whole contents. "
+				   "Note that this action can not be reverted, so you should double-check whether you "
+				   "selected the appropriate permissions.",
+				   "You are about to change the access rights to folders. "
+				   "You can apply these changes to the folders themselves only, or to their whole contents. "
+				   "Note that this action can not be reverted, so you should double-check whether you "
+				   "selected the appropriate permissions.",
+				   g_list_length (window->details->target_files)),
+			 _("Apply to Folder Only"),
+			 GTK_STOCK_CANCEL,
+			 ngettext ("Apply to Folder and Contents",
+				   "Apply to Folders and Contents",
+				   g_list_length (window->details->target_files)),
+			 NULL);
+
+		switch (res) {
+			case 0:
+				recursive = FALSE;
+				break;
+
+			case 1:
+				/* revert */
+				permission_combo_box_update (window, combo);
+				return;
+
+			case 2:
+				recursive = TRUE;
+				break;
+
+			default:
+				g_assert_not_reached ();
+		}
+	}
+
+	get_combo_permissions (combo,
+			       &file_on_permissions,
+			       &file_off_permissions,
+			       &folder_on_permissions,
+			       &folder_off_permissions);
+
+	/* combo boxes are instant apply */
+	schedule_permission_change (window, folder_on_permissions, TRUE, TRUE);
+	schedule_permission_change (window, folder_off_permissions, TRUE, FALSE);
+	schedule_permission_change (window, file_on_permissions, FALSE, TRUE);
+	schedule_permission_change (window, file_off_permissions, FALSE, FALSE);
+	apply_scheduled_permission_changes (window, recursive);
+
+	unschedule_permission_changes (window);
 }
 
 static void
-update_visibility_of_special_flags_widgets (FMPropertiesWindow *window)
+permission_combo_box_destroy (GtkComboBox *combo,
+			      FMPropertiesWindow *window)
 {
-	update_visibility_of_table_rows 
-		(window->details->permissions_table,
-		 eel_preferences_get_boolean (NAUTILUS_PREFERENCES_SHOW_SPECIAL_FLAGS),
-		 window->details->first_special_flags_row,
-		 window->details->num_special_flags_rows,
-		 window->details->special_flags_widgets);
+	g_assert (FM_IS_PROPERTIES_WINDOW (window));
+
+	window->details->permission_combo_boxes =
+		g_list_remove (window->details->permission_combo_boxes, combo);
 }
 
-static void
-update_visibility_of_special_flags_widgets_wrapper (gpointer callback_data)
+static GtkComboBox *
+attach_permission_combo_box (FMPropertiesWindow *window,
+			     GtkTable *table,
+			     SimplePermissionScope scope,
+			     unsigned int row)
 {
-	update_visibility_of_special_flags_widgets (FM_PROPERTIES_WINDOW (callback_data));
+	GtkComboBox *combo;
+
+	combo = attach_combo_box (table, row);
+	g_object_set_data (G_OBJECT (combo), "scope", GUINT_TO_POINTER (scope));
+
+	window->details->permission_combo_boxes = g_list_prepend
+		(window->details->permission_combo_boxes, combo);
+
+	permission_combo_box_update (window, combo);
+
+	g_signal_connect (combo, "changed",
+			  G_CALLBACK (permission_combo_box_changed),
+			  window);
+	g_signal_connect (combo, "destroy",
+			  G_CALLBACK (permission_combo_box_destroy),
+			  window);
+
+	return combo;
 }
 
 static void
-append_special_execution_flags (FMPropertiesWindow *window, GtkTable *table)
+permission_combo_box_update (FMPropertiesWindow *window,
+			     GtkComboBox *combo)
 {
-	
+	GtkTreeModel *model;
+	unsigned int n_cols;
+	gboolean all_directories, one_directory;
+	SimplePermissionScope scope;
+	GnomeVFSFilePermissions perms;
+	GnomeVFSFilePermissions r, w, x, all;
+	int i;
+
+	model = gtk_combo_box_get_model (combo);
 
-	remember_special_flags_widget (window, append_special_execution_checkbox 
-		(window, table, _("Set _user ID"), GNOME_VFS_PERM_SUID));
+	g_signal_handlers_block_by_func (G_OBJECT (combo),
+					 G_CALLBACK (permission_combo_box_changed),
+					 window);
 
-	window->details->first_special_flags_row = table->nrows - 1;
+	scope = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (combo), "scope"));
 
-	remember_special_flags_widget (window, GTK_WIDGET (attach_title_field 
-		(table, table->nrows - 1, _("Special flags:"))));
+	all_directories = file_list_all_directories (window->details->target_files,
+						     &one_directory);
+	g_object_set_data (G_OBJECT (combo), "is_folder", GUINT_TO_POINTER (all_directories));
 
-	remember_special_flags_widget (window, append_special_execution_checkbox 
-		(window, table, _("Set gro_up ID"), GNOME_VFS_PERM_SGID));
-	remember_special_flags_widget (window, append_special_execution_checkbox 
-		(window, table, _("_Sticky"), GNOME_VFS_PERM_STICKY));
+	n_cols = gtk_tree_model_iter_n_children (model, NULL);
 
-	remember_special_flags_widget (window, append_separator (table));
-	++window->details->num_special_flags_rows;
+	for (i = n_cols - 1; i >= 0; i--) {
+		gtk_combo_box_remove_text (combo, i);
+	}
 
-	update_visibility_of_special_flags_widgets (window);
-	eel_preferences_add_callback_while_alive 
-		(NAUTILUS_PREFERENCES_SHOW_SPECIAL_FLAGS,
-		 update_visibility_of_special_flags_widgets_wrapper,
-		 window,
-		 G_OBJECT (window));
-	
+	if (!all_directories && one_directory) {
+		/* leave empty */
+		goto unblock;
+	}
+
+	/* translators: DON'T include "Access|" in your translation */
+	gtk_combo_box_append_text (combo, _(Q_("Access|None")));
+
+	gtk_combo_box_append_text (combo, _("Read"));
+	gtk_combo_box_append_text (combo, _("Read, Write"));
+
+	if (!one_directory) {
+		/* don't offer x for folders, it will be set together with r */
+		gtk_combo_box_append_text (combo, _("Read, Execute"));
+		gtk_combo_box_append_text (combo, _("Read, Write, Execute"));
+	}
+
+	i = -1;
+
+	simple_permission_scope_to_vfs (scope, &r, &w, &x, &all);
+	if (file_list_same_permissions (window->details->target_files, all)) {
+		perms = nautilus_file_get_permissions (get_target_file (window));
+
+		i = simple_permission_scope_to_combo_box_iter (scope, one_directory, perms);
+	}
+
+	gtk_combo_box_set_active (combo, i);
+
+unblock:
+	g_signal_handlers_unblock_by_func (G_OBJECT (combo),
+					   G_CALLBACK (permission_combo_box_changed),
+					   window);
 }
 
 static gboolean
@@ -2860,6 +3519,7 @@ all_can_set_permissions (GList *file_lis
 	return TRUE;
 }
 
+/*
 static GHashTable *
 get_initial_permissions (GList *file_list)
 {
@@ -2881,197 +3541,624 @@ get_initial_permissions (GList *file_lis
 	}
 
 	return ret;
-}
+}*/
 
-static void
-create_permissions_page (FMPropertiesWindow *window)
-{
-	GtkWidget *vbox;
-	GtkTable *page_table, *check_button_table;
-	char *file_name, *prompt_text;
-	guint last_row;
-	guint checkbox_titles_row;
-	GtkLabel *group_label;
-	GtkLabel *owner_label;
-	GtkLabel *owner_perm_label;
-	GtkLabel *group_perm_label;
-	GtkLabel *other_perm_label;
-	GtkComboBox *group_combo_box;
-	GtkComboBox *owner_combo_box;
-	GList *file_list;
+typedef struct {
+	GList *permission_buttons;
 
-	vbox = create_page_with_vbox (window->details->notebook,
-				      _("Permissions"));
+	GtkVBox *vbox;
 
-	file_list = window->details->original_files;
+	GtkWidget *folder_permissions_table;
+	GtkLabel *folder_permissions_label;
 
-	window->details->initial_permissions = NULL;
-	
-	if (all_can_get_permissions (file_list)) {
-		window->details->initial_permissions = get_initial_permissions (window->details->target_files);
-		
-		if (!all_can_set_permissions (file_list)) {
-			add_prompt_and_separator (
-				GTK_VBOX (vbox), 
-				_("You are not the owner, so you can't change these permissions."));
-		}
+	GtkWidget *file_permissions_table;
+	GtkLabel *file_permissions_label;
 
-		page_table = GTK_TABLE (gtk_table_new (1, COLUMN_COUNT, FALSE));
-		window->details->permissions_table = page_table;
+	FMPropertiesWindow *properties_window;
+} PermissionDialogDetails;
 
-		apply_standard_table_padding (page_table);
-		last_row = 0;
-		gtk_widget_show (GTK_WIDGET (page_table));
-		gtk_box_pack_start (GTK_BOX (vbox), 
-				    GTK_WIDGET (page_table), 
-				    TRUE, TRUE, 0);
+static GtkWidget *
+create_permission_details_page_table (FMPropertiesWindow  *window,
+				      GList              **button_list,
+				      gboolean             is_folder,
+				      gboolean             append_info_fields)
+{
+	GtkTable *page_table;
+	GtkTable *check_button_table;
+	GtkLabel *owner_perm_label;
+	GtkLabel *group_perm_label;
+	GtkLabel *other_perm_label;
+	unsigned int checkbox_titles_row;
 
-		if (!is_multi_file_window (window) && nautilus_file_can_set_owner (get_target_file (window))) {
-			owner_label = attach_title_field (page_table, last_row, _("File _owner:"));
-			/* Combo box in this case. */
-			owner_combo_box = attach_owner_combo_box (page_table, last_row, get_target_file (window));
-			gtk_label_set_mnemonic_widget (owner_label,
-						       GTK_WIDGET (owner_combo_box));
-		} else {
-			attach_title_field (page_table, last_row, _("File owner:"));
-			/* Static text in this case. */
-			attach_value_field (window, 
-					    page_table, last_row, VALUE_COLUMN,
-					    "owner",
-					    _("--"),
-					    FALSE); 
-		}
+	page_table = GTK_TABLE (gtk_table_new (0, 0, FALSE));
+	gtk_widget_show (GTK_WIDGET (page_table));
 
-		if (!is_multi_file_window (window) && nautilus_file_can_set_group (get_target_file (window))) {
-			last_row = append_title_field (page_table,
-						       _("_File group:"),
-						       &group_label);
-			/* Combo box in this case. */
-			group_combo_box = attach_group_combo_box (page_table, last_row,
-								 get_target_file (window));
-			gtk_label_set_mnemonic_widget (group_label,
-						       GTK_WIDGET (group_combo_box));
-		} else {
-			last_row = append_title_field (page_table,
-						       _("File group:"),
-						       NULL);
-			/* Static text in this case. */
-			attach_value_field (window, page_table, last_row, 
-					    VALUE_COLUMN, 
-					    "group",
-					    _("--"),
-					    FALSE); 
-		}
+	checkbox_titles_row = append_title_field (page_table, _("Owner:"), &owner_perm_label);
+	append_title_field (page_table, _("Group:"), &group_perm_label);
+	append_title_field (page_table, _("Others:"), &other_perm_label);
+
+	check_button_table = GTK_TABLE (gtk_table_new 
+					   (PERMISSIONS_CHECKBOXES_ROW_COUNT, 
+					    PERMISSIONS_CHECKBOXES_COLUMN_COUNT, 
+					    FALSE));
+	apply_standard_table_padding (check_button_table);
+	gtk_widget_show (GTK_WIDGET (check_button_table));
+	gtk_table_attach (page_table, GTK_WIDGET (check_button_table),
+			  VALUE_COLUMN, VALUE_COLUMN + 1, 
+			  checkbox_titles_row, checkbox_titles_row + PERMISSIONS_CHECKBOXES_ROW_COUNT,
+			  0, 0,
+			  0, 0);
 
-		append_separator (page_table);
-		
-		checkbox_titles_row = append_title_field (page_table, _("Owner:"), &owner_perm_label);
-		append_title_field (page_table, _("Group:"), &group_perm_label);
-		append_title_field (page_table, _("Others:"), &other_perm_label);
-		
-		check_button_table = GTK_TABLE (gtk_table_new 
-						   (PERMISSIONS_CHECKBOXES_ROW_COUNT, 
-						    PERMISSIONS_CHECKBOXES_COLUMN_COUNT, 
-						    FALSE));
-		apply_standard_table_padding (check_button_table);
-		gtk_widget_show (GTK_WIDGET (check_button_table));
-		gtk_table_attach (page_table, GTK_WIDGET (check_button_table),
-				  VALUE_COLUMN, VALUE_COLUMN + 1, 
-				  checkbox_titles_row, checkbox_titles_row + PERMISSIONS_CHECKBOXES_ROW_COUNT,
-				  0, 0,
-				  0, 0);
-
-		add_permissions_checkbox (window,
-					  check_button_table, 
-					  PERMISSIONS_CHECKBOXES_OWNER_ROW,
-					  PERMISSIONS_CHECKBOXES_READ_COLUMN,
-					  GNOME_VFS_PERM_USER_READ,
-					  owner_perm_label);
-
-		add_permissions_checkbox (window,
-					  check_button_table, 
-					  PERMISSIONS_CHECKBOXES_OWNER_ROW,
-					  PERMISSIONS_CHECKBOXES_WRITE_COLUMN,
-					  GNOME_VFS_PERM_USER_WRITE,
-					  owner_perm_label);
-
-		add_permissions_checkbox (window,
-					  check_button_table, 
-					  PERMISSIONS_CHECKBOXES_OWNER_ROW,
-					  PERMISSIONS_CHECKBOXES_EXECUTE_COLUMN,
-					  GNOME_VFS_PERM_USER_EXEC,
-					  owner_perm_label);
-
-		add_permissions_checkbox (window,
-					  check_button_table, 
-					  PERMISSIONS_CHECKBOXES_GROUP_ROW,
-					  PERMISSIONS_CHECKBOXES_READ_COLUMN,
-					  GNOME_VFS_PERM_GROUP_READ,
-					  group_perm_label);
-
-		add_permissions_checkbox (window,
-					  check_button_table, 
-					  PERMISSIONS_CHECKBOXES_GROUP_ROW,
-					  PERMISSIONS_CHECKBOXES_WRITE_COLUMN,
-					  GNOME_VFS_PERM_GROUP_WRITE,
-					  group_perm_label);
-
-		add_permissions_checkbox (window,
-					  check_button_table, 
-					  PERMISSIONS_CHECKBOXES_GROUP_ROW,
-					  PERMISSIONS_CHECKBOXES_EXECUTE_COLUMN,
-					  GNOME_VFS_PERM_GROUP_EXEC,
-					  group_perm_label);
-
-		add_permissions_checkbox (window,
-					  check_button_table, 
-					  PERMISSIONS_CHECKBOXES_OTHERS_ROW,
-					  PERMISSIONS_CHECKBOXES_READ_COLUMN,
-					  GNOME_VFS_PERM_OTHER_READ,
-					  other_perm_label);
-
-		add_permissions_checkbox (window,
-					  check_button_table, 
-					  PERMISSIONS_CHECKBOXES_OTHERS_ROW,
-					  PERMISSIONS_CHECKBOXES_WRITE_COLUMN,
-					  GNOME_VFS_PERM_OTHER_WRITE,
-					  other_perm_label);
-
-		add_permissions_checkbox (window,
-					  check_button_table, 
-					  PERMISSIONS_CHECKBOXES_OTHERS_ROW,
-					  PERMISSIONS_CHECKBOXES_EXECUTE_COLUMN,
-					  GNOME_VFS_PERM_OTHER_EXEC,
-					  other_perm_label);
+	add_permissions_checkbox (window,
+				  check_button_table, 
+				  PERMISSIONS_CHECKBOXES_OWNER_ROW,
+				  PERMISSIONS_CHECKBOXES_READ_COLUMN,
+				  GNOME_VFS_PERM_USER_READ,
+				  NULL,
+				  owner_perm_label,
+				  button_list,
+				  is_folder);
+
+	add_permissions_checkbox (window,
+				  check_button_table, 
+				  PERMISSIONS_CHECKBOXES_OWNER_ROW,
+				  PERMISSIONS_CHECKBOXES_WRITE_COLUMN,
+				  GNOME_VFS_PERM_USER_WRITE,
+				  NULL,
+				  owner_perm_label,
+				  button_list,
+				  is_folder);
+
+	add_permissions_checkbox (window,
+				  check_button_table, 
+				  PERMISSIONS_CHECKBOXES_OWNER_ROW,
+				  PERMISSIONS_CHECKBOXES_EXECUTE_COLUMN,
+				  GNOME_VFS_PERM_USER_EXEC,
+				  NULL,
+				  owner_perm_label,
+				  button_list,
+				  is_folder);
+
+	add_permissions_checkbox (window,
+				  check_button_table, 
+				  PERMISSIONS_CHECKBOXES_GROUP_ROW,
+				  PERMISSIONS_CHECKBOXES_READ_COLUMN,
+				  GNOME_VFS_PERM_GROUP_READ,
+				  NULL,
+				  group_perm_label,
+				  button_list,
+				  is_folder);
+
+	add_permissions_checkbox (window,
+				  check_button_table, 
+				  PERMISSIONS_CHECKBOXES_GROUP_ROW,
+				  PERMISSIONS_CHECKBOXES_WRITE_COLUMN,
+				  GNOME_VFS_PERM_GROUP_WRITE,
+				  NULL,
+				  group_perm_label,
+				  button_list,
+				  is_folder);
+
+	add_permissions_checkbox (window,
+				  check_button_table, 
+				  PERMISSIONS_CHECKBOXES_GROUP_ROW,
+				  PERMISSIONS_CHECKBOXES_EXECUTE_COLUMN,
+				  GNOME_VFS_PERM_GROUP_EXEC,
+				  NULL,
+				  group_perm_label,
+				  button_list,
+				  is_folder);
+
+	add_permissions_checkbox (window,
+				  check_button_table, 
+				  PERMISSIONS_CHECKBOXES_OTHERS_ROW,
+				  PERMISSIONS_CHECKBOXES_READ_COLUMN,
+				  GNOME_VFS_PERM_OTHER_READ,
+				  NULL,
+				  other_perm_label,
+				  button_list,
+				  is_folder);
+
+	add_permissions_checkbox (window,
+				  check_button_table, 
+				  PERMISSIONS_CHECKBOXES_OTHERS_ROW,
+				  PERMISSIONS_CHECKBOXES_WRITE_COLUMN,
+				  GNOME_VFS_PERM_OTHER_WRITE,
+				  NULL,
+				  other_perm_label,
+				  button_list,
+				  is_folder);
+
+	add_permissions_checkbox (window,
+				  check_button_table, 
+				  PERMISSIONS_CHECKBOXES_OTHERS_ROW,
+				  PERMISSIONS_CHECKBOXES_EXECUTE_COLUMN,
+				  GNOME_VFS_PERM_OTHER_EXEC,
+				  NULL,
+				  other_perm_label,
+				  button_list,
+				  is_folder);
+
+	int row;
+	GtkLabel *special_flags_label;
+
+	row = append_title_field (page_table, _("Special flags:"), &special_flags_label);
+	add_permissions_checkbox (window,
+				  page_table,
+				  row,
+				  VALUE_COLUMN,
+				  GNOME_VFS_PERM_SUID,
+				  _("Set _user ID"),
+				  special_flags_label,
+				  button_list,
+				  is_folder);
+
+	row = append_row (page_table);
+	add_permissions_checkbox (window,
+				  page_table,
+				  row,
+				  VALUE_COLUMN,
+				  GNOME_VFS_PERM_SGID,
+				  _("Set _group ID"),
+				  special_flags_label,
+				  button_list,
+				  is_folder);
+
+	row = append_row (page_table);
+	add_permissions_checkbox (window,
+				  page_table,
+				  row,
+				  VALUE_COLUMN,
+				  GNOME_VFS_PERM_SGID,
+				  _("_Sticky"),
+				  special_flags_label,
+				  button_list,
+				  is_folder);
 
+	if (append_info_fields) {
+		/* FIXME use proper spacing */
 		append_separator (page_table);
 
-		append_special_execution_flags (window, page_table);
-		
 		append_title_value_pair
 			(window, page_table, _("Text view:"), 
 			 "permissions", _("--"),
-			 FALSE);
+			 FALSE,
+			 TRUE);
 		append_title_value_pair 
 			(window, page_table, _("Number view:"), 
 			 "octal_permissions", _("--"),
-			 FALSE);
-		append_title_value_pair
-			(window, page_table, _("Last changed:"), 
-			 "date_permissions", _("--"),
-			 FALSE);
-	} else {
-		if (!is_multi_file_window (window)) {
-			file_name = nautilus_file_get_display_name (get_target_file (window));
-			prompt_text = g_strdup_printf (_("The permissions of \"%s\" could not be determined."), file_name);
-			g_free (file_name);
-		} else {
-			prompt_text = g_strdup (_("The permissions of the selected file could not be determined."));
-		}
-		
+			 FALSE,
+			 TRUE);
+	}
+
+	/*
+	 * TODO decide whether this should really go in.
+	 * It involves mtime/ctime comparison, and thus is not very
+	 * verbose to 99.99% of the users.
+	append_title_value_pair
+		(window, page_table, _("Last changed:"), 
+		 "date_permissions", _("--"),
+		 FALSE,
+		 TRUE);*/
+
+	return GTK_WIDGET (page_table);
+}
+
+static GtkWidget *
+create_category_table (GtkWidget   *contents,
+		       GtkLabel   **label_ret)
+{
+	GtkTable *table;
+	GtkWidget *label;
+	GtkWidget *indent_label;
+
+	g_assert (contents != NULL);
+
+	table = GTK_TABLE (gtk_table_new (2, 2, FALSE));
+	gtk_table_set_row_spacings (GTK_TABLE (table), 6);
+	gtk_widget_show (GTK_WIDGET (table));
+
+	label = gtk_label_new (NULL);
+	eel_gtk_label_make_bold (GTK_LABEL (label));
+	gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+	gtk_widget_show (label);
+	gtk_table_attach (table, label,
+			  0, 2, 0, 1,
+			  GTK_EXPAND | GTK_FILL, 0,
+			  0, 0);
+
+	indent_label = gtk_label_new (NULL);
+	gtk_widget_set_size_request (indent_label, 12, -1);
+	gtk_widget_show (indent_label);
+	gtk_table_attach (table, indent_label,
+			  0, 1, 1, 2,
+			  GTK_FILL, 0,
+			  0, 0);
+
+	gtk_table_attach (table, contents,
+			  1, 2, 1, 2,
+			  GTK_EXPAND | GTK_FILL, 0,
+			  0, 0);
+
+	if (label_ret != NULL) {
+		*label_ret = GTK_LABEL (label);
+	}
+
+	return GTK_WIDGET (table);
+}
+
+static void
+restore_permission_button_labels (GtkDialog *dialog)
+{
+	PermissionDialogDetails *details;
+	GList *l;
+
+	g_assert (GTK_IS_DIALOG (dialog));
+
+	details = g_object_get_data (G_OBJECT (dialog), "details");
+	g_assert (details != NULL);
+
+	for (l = details->permission_buttons; l != NULL; l = l->next) {
+		eel_gtk_label_make_normal (GTK_LABEL (GTK_BIN (l->data)->child));
+	}
+}
+
+static void
+permission_details_dialog_response (GtkDialog *details_dialog,
+				    int response,
+				    FMPropertiesWindow *window)
+{
+	g_assert (FM_IS_PROPERTIES_WINDOW (window));
+
+	if (response == GTK_RESPONSE_OK) {
+		apply_scheduled_permission_changes (window, TRUE);
+		restore_permission_button_labels (details_dialog);
+	}
+
+	unschedule_permission_changes (window);
+	gtk_widget_destroy (GTK_WIDGET (details_dialog));
+}
+
+static void
+free_dialog_details (PermissionDialogDetails *details)
+{
+	g_object_unref (details->properties_window);
+	g_list_free (details->permission_buttons);
+	g_free (details);
+}
+
+static void
+permission_details_dialog_update_labels (GtkDialog *dialog)
+{
+	PermissionDialogDetails *details;
+	char *file_title, *folder_title;
+
+	g_assert (GTK_IS_DIALOG (dialog));
+
+	details = g_object_get_data (G_OBJECT (dialog), "details");
+	g_assert (details != NULL);
+
+	if (!is_multi_file_window (details->properties_window)) {
+		char *uri;
+
+		uri = nautilus_file_get_display_name (get_target_file (details->properties_window));
+
+		folder_title = g_strdup_printf (_("\"%s\" and Subfolders"), uri);
+
+		file_title = g_strdup_printf (_("Files in \"%s\" and in Subfolders"), uri);
+
+		g_free (uri);
+	} else {
+		folder_title = g_strdup (ngettext ("Folder and Subfolders",
+						   "Folders and Subfolders",
+						   g_list_length (details->properties_window->details->target_files)));
+
+		file_title = g_strdup (ngettext ("Files in Folder and in Subfolders",
+						 "Files in Folders and in Subfolders",
+						 g_list_length (details->properties_window->details->target_files)));
+	}
+
+	if (details->folder_permissions_label != NULL) {
+		gtk_label_set_text (details->folder_permissions_label, folder_title);
+	}
+
+	if (details->file_permissions_label != NULL) {
+		gtk_label_set_text (details->file_permissions_label, file_title);
+	}
+
+	g_free (folder_title);
+	g_free (file_title);
+}
+
+static GtkDialog *
+create_permission_details_dialog (FMPropertiesWindow *window)
+{
+	GtkWidget *dialog;
+	PermissionDialogDetails *details;
+	gboolean all_dirs;
+	gboolean one_dir;
+
+	// FIXME should this really be asserted?
+	all_dirs = file_list_all_directories (window->details->target_files, &one_dir);
+	g_assert (all_dirs || !one_dir);
+
+	dialog = gtk_dialog_new_with_buttons (_("Access Details"),
+					      GTK_WINDOW (window),
+					      GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
+					      GTK_STOCK_CANCEL, GTK_STOCK_CANCEL,
+					      GTK_STOCK_OK, GTK_RESPONSE_OK,
+					      NULL);
+	gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_OK, FALSE);
+
+	/* TODO - this should be done inside GTK+ */
+	gtk_widget_ensure_style (dialog);
+	gtk_container_set_border_width (GTK_CONTAINER (dialog), 12);
+	gtk_box_set_spacing (GTK_BOX (GTK_DIALOG (dialog)->vbox), 12);
+	gtk_container_set_border_width (GTK_CONTAINER (GTK_DIALOG (dialog)->action_area), 0);
+	gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE);
+
+	/* Allocate details structure */
+	details = g_new (PermissionDialogDetails, 1);
+	g_object_set_data_full (G_OBJECT (dialog),
+				"details",
+				details,
+				(GDestroyNotify) free_dialog_details);
+
+	details->properties_window = g_object_ref (window);
+
+	details->vbox = GTK_VBOX (gtk_vbox_new (FALSE, 18));
+	gtk_widget_show (GTK_WIDGET (details->vbox));
+	gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), GTK_WIDGET (details->vbox));
+
+	details->permission_buttons = NULL;
+
+	/* Folders page */
+	details->folder_permissions_table = create_permission_details_page_table
+		(window, &details->permission_buttons, TRUE, TRUE);
+
+	/* Files page */
+	details->file_permissions_table = create_permission_details_page_table
+		(window, &details->permission_buttons, FALSE, !all_dirs);
+
+	window->details->permission_details_dialog = (GtkDialog *) dialog;
+	g_object_add_weak_pointer (G_OBJECT (dialog),
+				   (gpointer *) &window->details->permission_details_dialog);
+
+	g_signal_connect (dialog, "response",
+			  G_CALLBACK (permission_details_dialog_response),
+			  window);
+
+	return GTK_DIALOG (dialog);
+}
+
+static void
+permission_details_dialog_update (GtkDialog *dialog)
+{
+	PermissionDialogDetails *details;
+	FMPropertiesWindow *window;
+	GList *l;
+	gboolean one_directory;
+
+	details = g_object_get_data (G_OBJECT (dialog), "details");
+	g_assert (details != NULL);
+
+	window = (FMPropertiesWindow *) gtk_window_get_transient_for (GTK_WINDOW (dialog));
+	g_assert (FM_IS_PROPERTIES_WINDOW (window));
+
+	for (l = details->permission_buttons; l != NULL; l = l->next) {
+		permission_button_update (window, GTK_TOGGLE_BUTTON (l->data));
+	}
+
+	gtk_widget_unparent (details->folder_permissions_table);
+	gtk_widget_unparent (details->file_permissions_table);
+
+	details->folder_permissions_label = NULL;
+	details->file_permissions_label = NULL;
+
+	gtk_container_foreach (GTK_CONTAINER (details->vbox),
+			       (GtkCallback) gtk_widget_destroy,
+			       NULL);
+
+	if (file_list_all_directories (window->details->target_files, &one_directory)) {
+		GtkWidget *table;
+
+		table = create_category_table (details->folder_permissions_table,
+					       &details->folder_permissions_label);
+		gtk_box_pack_start (GTK_BOX (details->vbox),
+				    table,
+				    TRUE, TRUE, 0);
+		g_object_add_weak_pointer (G_OBJECT (details->folder_permissions_label),
+					   (gpointer *) &details->folder_permissions_label);
+
+		table = create_category_table (details->file_permissions_table,
+					       &details->file_permissions_label);
+		gtk_box_pack_start (GTK_BOX (details->vbox),
+				    table,
+				    TRUE, TRUE, 0);
+		g_object_add_weak_pointer (G_OBJECT (details->file_permissions_label),
+					   (gpointer *) &details->file_permissions_label);
+	} else if (!one_directory) {
+		gtk_box_pack_start (GTK_BOX (details->vbox),
+				    details->file_permissions_table,
+				    TRUE, TRUE, 0);
+	} else {
+		add_prompt (GTK_VBOX (details->vbox),
+			    _("You selected files and folders, but you can only modify their access rights separately."),
+			    TRUE);
+	}
+
+	permission_details_dialog_update_labels (dialog);
+}
+
+static void
+show_permission_details_dialog (GtkButton *details_button,
+				FMPropertiesWindow *window)
+{
+	GtkDialog *dialog;
+
+	if (window->details->permission_details_dialog != NULL) {
+		/* this is required because some WMs might not respect modality. */
+		gtk_window_present (GTK_WINDOW (window->details->permission_details_dialog));
+		return;
+	}
+
+	dialog = create_permission_details_dialog (window);
+
+	permission_details_dialog_update (GTK_DIALOG (dialog));
+	gtk_dialog_run (dialog);
+}
+
+static void
+create_permissions_page (FMPropertiesWindow *window)
+{
+	GtkTable *table;
+	GtkLabel *label;
+	GtkWidget *vbox;
+	GtkComboBox *combo;
+	GtkWidget *alignment;
+	GtkWidget *button;
+	unsigned int last_row;
+	char *file_name;
+	char *prompt_text;
+	gboolean one_directory;
+
+	vbox = create_page_with_vbox (window->details->notebook, _("Access Rights"));
+
+	if (!is_multi_file_window (window) &&
+	    !all_can_get_permissions (window->details->original_files)) {
+		file_name = nautilus_file_get_display_name (get_target_file (window));
+
+		prompt_text = g_strdup_printf (_("The access rights of \"%s\" could not be determined."), file_name);
 		add_prompt (GTK_VBOX (vbox), prompt_text, TRUE);
+
 		g_free (prompt_text);
+		g_free (file_name);
+
+		return;
+	} else if (!all_can_get_permissions (window->details->original_files)) {
+		add_prompt (GTK_VBOX (vbox),
+			    ngettext ("The access rights of the selected file could not be determined.",
+				      "The access rights of the selected files could not be determined.",
+				      g_list_length (window->details->original_files)),
+			    TRUE);
+
+		return;
+	} else if (!is_multi_file_window (window) &&
+		   !all_can_set_permissions(window->details->original_files)) {
+		file_name = nautilus_file_get_display_name (get_target_file (window));
+
+		prompt_text = g_strdup_printf (_("You are not the owner of \"%s\", so you can not change its access rights."), file_name);
+		add_prompt (GTK_VBOX (vbox), prompt_text, TRUE);
+
+		g_free (prompt_text);
+		g_free (file_name);
+
+		return;
+	} else if (!all_can_set_permissions (window->details->original_files)) {
+		add_prompt (GTK_VBOX (vbox),
+			    ngettext ("You are not the owner of the selected file, so you can not change its access rights.",
+				      "You are not the owner of the selected files, so you can not change their access rights.",
+				      g_list_length (window->details->original_files)),
+			    TRUE);
+
+		return;
+	} else if (!file_list_all_directories (window->details->target_files, &one_directory) &&
+		   one_directory) {
+		/* It's unclear how to build an intuitive GUI for both files and folders
+		 * which does not mess up with the "Execute" bits. */
+		add_prompt (GTK_VBOX (vbox),
+			    _("You selected files and folders, but you can only modify their access rights separately."),
+			    TRUE);
+		return;
 	}
+
+
+	table = GTK_TABLE (create_attribute_value_table (GTK_VBOX (vbox), 0));
+
+	if (!is_multi_file_window (window) &&
+	    nautilus_file_can_set_owner (get_target_file (window))) {
+		last_row = append_title_field (table, _("_Owner:"), &label);
+		/* Combo box in this case. */
+		combo = attach_owner_combo_box (table, last_row, get_target_file (window));
+		gtk_label_set_mnemonic_widget (label, GTK_WIDGET (combo));
+	} else {
+		last_row = append_title_field (table, _("Owner:"), &label);
+		/* Static text in this case. */
+		attach_value_field (window, 
+				    table, last_row, VALUE_COLUMN,
+				    "owner",
+				    _("--"),
+				    FALSE,
+				    FALSE); 
+	}
+
+	last_row = append_title_field (table, _("_Access:"), NULL);
+
+	combo = attach_permission_combo_box (window,
+					     table,
+					     SIMPLE_PERMISSIONS_SCOPE_USER,
+					     last_row);
+
+	/* FIXME use proper spacing */
+	last_row = append_title_field (table, NULL, NULL);
+
+	/* Group */
+	if (!is_multi_file_window (window) &&
+	    nautilus_file_can_set_group (get_target_file (window))) {
+		last_row = append_title_field (table,
+					       _("_Group:"),
+					       &label);
+		/* Combo box in this case. */
+		combo = attach_group_combo_box (table, last_row, get_target_file (window));
+		gtk_label_set_mnemonic_widget (label, GTK_WIDGET (combo));
+	} else {
+		last_row = append_title_field (table,
+					       _("Group:"),
+					       NULL);
+		/* Static text in this case. */
+		attach_value_field (window, table, last_row, 
+				    VALUE_COLUMN, 
+				    "group",
+				    _("--"),
+				    FALSE,
+				    FALSE); 
+	}
+
+	last_row = append_title_field (table, _("A_ccess:"), NULL);
+
+	combo = attach_permission_combo_box (window,
+					     table,
+					     SIMPLE_PERMISSIONS_SCOPE_GROUP,
+					     last_row);
+
+	/* FIXME use proper spacing */
+	last_row = append_title_field (table, NULL, NULL);
+
+	/* Others */
+	last_row = append_title_field (table, _("_Others:"), NULL);
+	combo = attach_permission_combo_box (window,
+					     table,
+					     SIMPLE_PERMISSIONS_SCOPE_OTHER,
+					     last_row);
+
+	/* FIXME use proper spacing */
+	last_row = append_row (table);
+
+	alignment = gtk_alignment_new (1.0, 0.5, 0.0, 0.0);
+	gtk_widget_show (alignment);
+	gtk_table_attach (table, alignment,
+			  TITLE_COLUMN, VALUE_COLUMN + 1,
+			  last_row, last_row + 1,
+			  GTK_FILL, 0,
+			  0, 0);
+
+	button = gtk_button_new_with_mnemonic ("_Details");
+	gtk_widget_show (button);
+	gtk_container_add (GTK_CONTAINER (alignment), button);
+
+	g_signal_connect (button, "clicked",
+			  G_CALLBACK (show_permission_details_dialog),
+			  window);
 }
 
 static void
@@ -3667,9 +4754,6 @@ real_destroy (GtkObject *object)
  
 	window->details->name_field = NULL;
 
-	g_list_free (window->details->special_flags_widgets);
-	window->details->special_flags_widgets = NULL;
-
 	g_list_free (window->details->emblem_buttons);
 	window->details->emblem_buttons = NULL;
 
@@ -3677,9 +4761,6 @@ real_destroy (GtkObject *object)
 		g_hash_table_destroy (window->details->initial_emblems);
 		window->details->initial_emblems = NULL;
 	}
-
-	g_list_free (window->details->permission_buttons);
-	window->details->permission_buttons = NULL;
 
 	if (window->details->initial_permissions) {
 		g_hash_table_destroy (window->details->initial_permissions);
