Index: src/file-manager/fm-properties-window.c
===================================================================
RCS file: /cvs/gnome/nautilus/src/file-manager/fm-properties-window.c,v
retrieving revision 1.216
diff -u -p -r1.216 fm-properties-window.c
--- src/file-manager/fm-properties-window.c	2 Jun 2005 16:16:56 -0000	1.216
+++ src/file-manager/fm-properties-window.c	10 Jul 2005 12:20:47 -0000
@@ -97,8 +97,14 @@ struct FMPropertiesWindowDetails {	
 
 	GtkWidget *name_label;
 	GtkWidget *name_field;
+	unsigned int name_row;
 	char *pending_name;
 
+	GtkWidget *link_label;
+	GtkWidget *link_field;
+	unsigned int link_row;
+	char *pending_link;
+
 	GtkLabel *directory_contents_title_field;
 	GtkLabel *directory_contents_value_field;
 	guint update_directory_contents_timeout_id;
@@ -205,16 +211,21 @@ static void remove_pending              
 						   gboolean            cancel_destroy_handler);
 static void append_extension_pages                (FMPropertiesWindow *window);
 
-static gboolean name_field_focus_out              (NautilusEntry *name_field,
+static gboolean field_focus_out                   (NautilusEntry *field,
 						   GdkEventFocus *event,
 						   gpointer callback_data);
-static void name_field_activate                   (NautilusEntry *name_field,
+static void     field_activate                    (NautilusEntry *field,
 						   gpointer callback_data);
 static GtkLabel *attach_ellipsizing_value_label   (GtkTable *table,
 						   int row,
 						   int column,
 						   const char *initial_text);
 
+static void apply_name_field_changes              (const char *value,
+						   FMPropertiesWindow *window);
+static void apply_link_field_changes              (const char *value,
+						   FMPropertiesWindow *window);
+
 GNOME_CLASS_BOILERPLATE (FMPropertiesWindow, fm_properties_window,
 			 GtkWindow, GTK_TYPE_WINDOW);
 
@@ -223,6 +234,9 @@ typedef struct {
 	char *name;
 } FileNamePair;
 
+typedef void (* ApplyFieldChangesFunc) (const char         *value,
+					FMPropertiesWindow *window);
+
 static FileNamePair *
 file_name_pair_new (NautilusFile *file, const char *name)
 {
@@ -556,12 +570,21 @@ create_image_widget (FMPropertiesWindow 
 }
 
 static void
-set_name_field (FMPropertiesWindow *window, const gchar *original_name,
-					 const gchar *name)
+set_field (FMPropertiesWindow *window,
+	   GtkWidget *label,
+	   GtkWidget **field,
+	   unsigned int row,
+	   const char *value,
+	   const char *original_value,
+	   ApplyFieldChangesFunc apply_field_changes_func)
 {
 	gboolean new_widget;
 	gboolean use_label;
 
+	g_assert (label != NULL);
+	g_assert (field != NULL);
+	g_assert (apply_field_changes_func != NULL);
+
 	/* There are four cases here:
 	 * 1) Changing the text of a label
 	 * 2) Changing the text of an entry
@@ -569,27 +592,27 @@ set_name_field (FMPropertiesWindow *wind
 	 * 4) Creating entry (potentially replacing label)
 	 */
 	use_label = is_multi_file_window (window) || !nautilus_file_can_rename (get_original_file (window));
-	new_widget = !window->details->name_field || (use_label ? NAUTILUS_IS_ENTRY (window->details->name_field) : GTK_IS_LABEL (window->details->name_field));
+	new_widget = *field == NULL || (use_label ? NAUTILUS_IS_ENTRY (*field) : GTK_IS_LABEL (*field));
 
 	if (new_widget) {
-		if (window->details->name_field) {
-			gtk_widget_destroy (window->details->name_field);
+		if (*field) {
+			gtk_widget_destroy (*field);
 		}
 
 		if (use_label) {
-			window->details->name_field = GTK_WIDGET (attach_ellipsizing_value_label (window->details->basic_table, 0, VALUE_COLUMN, name));		
+			*field = GTK_WIDGET (attach_ellipsizing_value_label (window->details->basic_table, 0, VALUE_COLUMN, value));		
 		} else {
-			window->details->name_field = nautilus_entry_new ();
-			gtk_entry_set_text (GTK_ENTRY (window->details->name_field), name);
-			gtk_widget_show (window->details->name_field);
+			*field = nautilus_entry_new ();
+			gtk_entry_set_text (GTK_ENTRY (*field), value);
+			gtk_widget_show (*field);
 			gtk_table_attach (window->details->basic_table,
-					  window->details->name_field,
+					  *field,
 					  VALUE_COLUMN, 
 					  VALUE_COLUMN + 1,
-					  0, 1,
+					  row, row + 1,
 					  GTK_FILL, 0,
 					  0, 0);
-			gtk_label_set_mnemonic_widget (GTK_LABEL (window->details->name_label), window->details->name_field);
+			gtk_label_set_mnemonic_widget (GTK_LABEL (label), *field);
 			
 			/* FIXME bugzilla.gnome.org 42151:
 			 * With this (and one place elsewhere in this file, not sure which is the
@@ -601,33 +624,36 @@ set_name_field (FMPropertiesWindow *wind
 			 */
 #ifdef UNDO_ENABLED
 			/* Set up name field for undo */
-			nautilus_undo_set_up_nautilus_entry_for_undo ( NAUTILUS_ENTRY (window->details->name_field));
-			nautilus_undo_editable_set_undo_key (GTK_EDITABLE (window->details->name_field), TRUE);
+			nautilus_undo_set_up_nautilus_entry_for_undo (NAUTILUS_ENTRY (*field));
+			nautilus_undo_editable_set_undo_key (GTK_EDITABLE (*field), TRUE);
 #endif
 
-			g_signal_connect_object (window->details->name_field, "focus_out_event",
-						 G_CALLBACK (name_field_focus_out), window, 0);
-			g_signal_connect_object (window->details->name_field, "activate",
-						 G_CALLBACK (name_field_activate), window, 0);
+			g_object_set_data (G_OBJECT (*field), "apply_changes_func",
+							      apply_field_changes_func);
+
+			g_signal_connect_object (*field, "focus_out_event",
+						 G_CALLBACK (field_focus_out), window, 0);
+			g_signal_connect_object (*field, "activate",
+						 G_CALLBACK (field_activate), window, 0);
 		}
 
 		gtk_widget_show (window->details->name_field);
 	}
-	/* Only replace text if the file's name has changed. */ 
-	else if (original_name == NULL || strcmp (original_name, name) != 0) {
+	/* Only replace text if the value has changed. */ 
+	else if (original_value == NULL || strcmp (original_value, value) != 0) {
 		
 		if (use_label) {
-			gtk_label_set_text (GTK_LABEL (window->details->name_field), name);
+			gtk_label_set_text (GTK_LABEL (*field), value);
 		} else {
 			/* Only reset the text if it's different from what is
 			 * currently showing. This causes minimal ripples (e.g.
 			 * selection change).
 			 */
-			gchar *displayed_name = gtk_editable_get_chars (GTK_EDITABLE (window->details->name_field), 0, -1);
-			if (strcmp (displayed_name, name) != 0) {
-				gtk_entry_set_text (GTK_ENTRY (window->details->name_field), name);
+			char *displayed_value = gtk_editable_get_chars (GTK_EDITABLE (*field), 0, -1);
+			if (strcmp (displayed_value, value) != 0) {
+				gtk_entry_set_text (GTK_ENTRY (*field), value);
 			}
-			g_free (displayed_name);
+			g_free (displayed_value);
 		}
 	}
 }
@@ -662,7 +688,14 @@ update_name_field (FMPropertiesWindow *w
 				g_free (name);
 			}
 		}
-		set_name_field (window, NULL, str->str);
+
+		set_field (window,
+			   window->details->name_label,
+			   &window->details->name_field,
+			   window->details->name_row,
+			   str->str,
+			   NULL,
+			   apply_name_field_changes);
 		g_string_free (str, TRUE);
 	} else {
 		const char *original_name = NULL;
@@ -682,15 +715,21 @@ update_name_field (FMPropertiesWindow *w
 		 * aspect of the file might have), then don't clobber changes.
 		 */
 		if (window->details->name_field) {
-			original_name = (const char *) g_object_get_data (G_OBJECT (window->details->name_field), "original_name");
+			original_name = (const char *) g_object_get_data (G_OBJECT (window->details->name_field), "original_value");
 		}
 
-		set_name_field (window, original_name, current_name);
+		set_field (window,
+			   window->details->name_label,
+			   &window->details->name_field,
+			   window->details->name_row,
+			   current_name,
+			   original_name,
+			   apply_name_field_changes);
 
 		if (original_name == NULL || 
 		    eel_strcmp (original_name, current_name) != 0) {
 			g_object_set_data_full (G_OBJECT (window->details->name_field),
-						"original_name",
+						"original_value",
 						current_name,
 						g_free);
 		} else {
@@ -700,26 +739,70 @@ update_name_field (FMPropertiesWindow *w
 }
 
 static void
-name_field_restore_original_name (NautilusEntry *name_field)
+update_link_field (FMPropertiesWindow *window)
 {
-	const char *original_name;
-	char *displayed_name;
+	NautilusFile *file;
+	const char *original_link = NULL;
+	char *current_link;
+
+	file = get_original_file (window);
+
+	if (file == NULL || nautilus_file_is_gone (file)) {
+		current_link = g_strdup ("");
+	} else {
+		current_link = nautilus_file_get_symbolic_link_target_path (file);
+	}
+
+	/* If the link target has changed since the original link was stored,
+	 * update the text in the text field, possibly (deliberately) clobbering
+	 * an edit in progress. If the link hasn't changed (but some other
+	 * aspect of the file might have), then don't clobber changes.
+	 */
+	if (window->details->link_field) {
+		original_link = (const char *) g_object_get_data (G_OBJECT (window->details->link_field), "original_value");
+	}
+
+	set_field (window,
+		   window->details->link_label,
+		   &window->details->link_field,
+		   window->details->link_row,
+		   current_link,
+		   original_link,
+		   apply_link_field_changes);
+
+	if (original_link == NULL || 
+	    eel_strcmp (original_link, current_link) != 0) {
+		g_object_set_data_full (G_OBJECT (window->details->link_field),
+					"original_value",
+					current_link,
+					g_free);
+	} else {
+		g_free (current_link);
+	}
+}
 
-	original_name = (const char *) g_object_get_data (G_OBJECT (name_field),
-							  "original_name");
 
-	if (!original_name) {
+static void
+field_restore_original_value (NautilusEntry *field)
+{
+	const char *original_value;
+	char *displayed_value;
+
+	original_value = (const char *) g_object_get_data (G_OBJECT (field),
+							  "original_value");
+
+	if (!original_value) {
 		return;
 	}
 
-	displayed_name = gtk_editable_get_chars (GTK_EDITABLE (name_field), 0, -1);
+	displayed_value = gtk_editable_get_chars (GTK_EDITABLE (field), 0, -1);
 
-	if (strcmp (original_name, displayed_name) != 0) {
-		gtk_entry_set_text (GTK_ENTRY (name_field), original_name);
+	if (strcmp (original_value, displayed_value) != 0) {
+		gtk_entry_set_text (GTK_ENTRY (field), original_value);
 	}
-	nautilus_entry_select_all (name_field);
+	nautilus_entry_select_all (field);
 
-	g_free (displayed_name);
+	g_free (displayed_value);
 }
 
 static void
@@ -738,7 +821,7 @@ rename_callback (NautilusFile *file, Gno
 					       result,
 					       GTK_WINDOW (window));
 		if (window->details->name_field != NULL) {
-			name_field_restore_original_name (NAUTILUS_ENTRY (window->details->name_field));
+			field_restore_original_value (NAUTILUS_ENTRY (window->details->name_field));
 		}
 	}
 
@@ -752,14 +835,38 @@ set_pending_name (FMPropertiesWindow *wi
 	window->details->pending_name = g_strdup (name);
 }
 
+
 static void
-name_field_done_editing (NautilusEntry *name_field, FMPropertiesWindow *window)
+apply_name_field_changes (const char *value,
+			  FMPropertiesWindow *window)
+{
+	NautilusFile *file;
+
+	set_pending_name (window, value);
+
+	file = get_original_file (window);
+	g_object_ref (window);
+	nautilus_file_rename (file, value,
+			      rename_callback, window);
+}
+
+static void
+apply_link_field_changes (const char *value,
+			  FMPropertiesWindow *window)
+{
+	/* TODO symlink relinking not supported by GnomeVFS */
+}
+
+static void
+field_done_editing (NautilusEntry *field,
+		    FMPropertiesWindow *window)
 {
 	NautilusFile *file;
 	char *new_name;
 	const char *original_name;
+	ApplyFieldChangesFunc apply_field_changes_func;
 	
-	g_return_if_fail (NAUTILUS_IS_ENTRY (name_field));
+	g_return_if_fail (NAUTILUS_IS_ENTRY (field));
 
 	/* Don't apply if the dialog has more than one file */
 	if (is_multi_file_window (window)) {
@@ -775,22 +882,23 @@ name_field_done_editing (NautilusEntry *
 		return;
 	}
 
-	new_name = gtk_editable_get_chars (GTK_EDITABLE (name_field), 0, -1);
+	new_name = gtk_editable_get_chars (GTK_EDITABLE (field), 0, -1);
 
 	/* Special case: silently revert text if new text is empty. */
 	if (strlen (new_name) == 0) {
-		name_field_restore_original_name (NAUTILUS_ENTRY (name_field));
+		field_restore_original_value (NAUTILUS_ENTRY (field));
 	} else {
-		original_name = (const char *) g_object_get_data (G_OBJECT (window->details->name_field),
-								  "original_name");
+		original_name = (const char *) g_object_get_data (G_OBJECT (field),
+								  "original_value");
 		/* Don't rename if not changed since we read the display name.
 		   This is needed so that we don't save the display name to the
 		   file when nothing is changed */
 		if (strcmp (new_name, original_name) != 0) {		
-			set_pending_name (window, new_name);
-			g_object_ref (window);
-			nautilus_file_rename (file, new_name,
-					      rename_callback, window);
+			apply_field_changes_func =
+				(ApplyFieldChangesFunc) g_object_get_data (G_OBJECT (field),
+									   "apply_changes_func");
+
+			apply_field_changes_func (new_name, window);
 		}
 	}
 
@@ -798,29 +906,29 @@ name_field_done_editing (NautilusEntry *
 }
 
 static gboolean
-name_field_focus_out (NautilusEntry *name_field,
-		      GdkEventFocus *event,
-		      gpointer callback_data)
+field_focus_out (NautilusEntry *field,
+		 GdkEventFocus *event,
+		 gpointer callback_data)
 {
 	g_assert (FM_IS_PROPERTIES_WINDOW (callback_data));
 
-	if (GTK_WIDGET_SENSITIVE (name_field)) {
-		name_field_done_editing (name_field, FM_PROPERTIES_WINDOW (callback_data));
+	if (GTK_WIDGET_SENSITIVE (field)) {
+		field_done_editing (field, FM_PROPERTIES_WINDOW (callback_data));
 	}
 
 	return FALSE;
 }
 
 static void
-name_field_activate (NautilusEntry *name_field, gpointer callback_data)
+field_activate (NautilusEntry *field, gpointer callback_data)
 {
-	g_assert (NAUTILUS_IS_ENTRY (name_field));
+	g_assert (NAUTILUS_IS_ENTRY (field));
 	g_assert (FM_IS_PROPERTIES_WINDOW (callback_data));
 
 	/* Accept changes. */
-	name_field_done_editing (name_field, FM_PROPERTIES_WINDOW (callback_data));
+	field_done_editing (field, FM_PROPERTIES_WINDOW (callback_data));
 
-	nautilus_entry_select_all_at_idle (name_field);
+	nautilus_entry_select_all_at_idle (field);
 }
 
 static gboolean
@@ -2342,6 +2450,7 @@ create_basic_page (FMPropertiesWindow *w
 	gtk_widget_show (name_label);
 	gtk_box_pack_end (GTK_BOX (hbox), name_label, FALSE, FALSE, 0);
 	window->details->name_label = name_label;
+	window->details->name_row = 0;
 
 	/* Name field */
 	window->details->name_field = NULL;
@@ -2389,11 +2498,19 @@ create_basic_page (FMPropertiesWindow *w
 	}
 
 	if (should_show_link_target (window)) {
+		window->details->link_row =
+			append_title_field (table, _("_Link target:"),
+					    (GtkLabel **) &window->details->link_label);
+
+		window->details->link_field = NULL;
+		update_link_field (window);
+
+		/*
 		append_title_and_ellipsizing_value (window, table, 
 						    _("Link target:"), 
 						    "link_target",
 						    _("--"),
-						    FALSE);
+						    FALSE);*/
 	}
 	if (should_show_mime_type (window)) {
 		append_title_value_pair (window, table, _("MIME type:"), 
