summaryrefslogtreecommitdiff
path: root/src/file-manager/fm-properties-window.c
diff options
context:
space:
mode:
authorDave Camp <dave@ximian.com>2003-06-08 08:45:15 +0000
committerDave Camp <campd@src.gnome.org>2003-06-08 08:45:15 +0000
commit9d4fe3275435ac10eb16963a257e02de19dd396f (patch)
tree13bb6d5fc81d1b5a3cf12fbf07ae0f929b952274 /src/file-manager/fm-properties-window.c
parentb93efdc7a31f36d50944bf8f3d26474823bc55ca (diff)
downloadnautilus-9d4fe3275435ac10eb16963a257e02de19dd396f.tar.gz
Implement multi-file property dialogs.
2003-06-08 Dave Camp <dave@ximian.com> * src/file-manager/fm-properties-window.h: * libnautilus-private/nautilus-mime-actions.c: (has_server_info_in_list), (server_info_list_intersection), (nautilus_mime_get_property_components_for_files): * libnautilus-private/nautilus-mime-actions.h: * src/file-manager/fm-directory-view.c: (open_properties_window_callback), (open_one_in_new_window): * src/file-manager/fm-properties-window.c: (is_multi_file_window), (get_original_file), (get_target_file_for_original_file), (get_target_file), (add_prompt_and_separator), (get_pixbuf_for_properties_window), (reset_icon), (create_image_widget_for_file), (update_name_field), (name_field_restore_original_name), (name_field_done_editing), (file_has_keyword), (get_initial_emblem_state), (emblem_button_toggled), (emblem_button_update), (update_properties_window_title), (remove_from_dialog), (mime_list_equal), (get_mime_list), (properties_window_update), (file_list_attributes_identical), (file_list_get_string_attribute), (file_list_all_local), (file_list_all_directories), (value_field_update_internal), (value_field_update), (attach_value_field_internal), (attach_value_field), (attach_ellipsizing_value_field), (append_separator), (directory_contents_value_field_update), (attach_directory_contents_value_field), (append_title_value_pair), (append_title_and_ellipsizing_value), (update_visibility_of_item_count_fields), (should_show_custom_icon_buttons), (should_show_file_type), (should_show_accessed_date), (should_show_mime_type), (should_show_link_target), (should_show_free_space), (create_basic_page), (get_initial_emblems), (create_emblems_page), (permission_change_callback), (get_initial_permission_state), (permission_button_toggled), (permission_button_update), (set_up_permissions_checkbox), (add_permissions_checkbox), (append_special_execution_checkbox), (append_special_execution_flags), (all_can_get_permissions), (all_can_set_permissions), (get_initial_permissions), (create_permissions_page), (get_uri_list), (bonobo_page_activate_callback), (can_handle_multiple_files), (append_bonobo_pages), (should_show_emblems), (should_show_permissions), (get_pending_key), (startup_data_new), (startup_data_free), (create_properties_window), (get_target_file_list), (add_window), (remove_window), (get_existing_window), (cancel_create_properties_window_callback), (directory_view_destroyed_callback), (cancel_call_when_ready_callback), (remove_pending), (is_directory_ready_callback), (fm_properties_window_present), (real_destroy), (real_finalize), (set_icon_callback), (select_image_button_callback), (remove_image_button_callback): Implement multi-file property dialogs. * components/image_properties/Nautilus_View_image_properties.server .in.in: * components/image_properties/nautilus-image-properties-view.c: (nautilus_image_properties_view_finalize), (get_property), (set_property), (nautilus_image_properties_view_init): * components/notes/Nautilus_View_notes.server.in.in: * components/notes/nautilus-notes.c: (set_bonobo_properties), (make_notes_view): Use new multipage property.
Diffstat (limited to 'src/file-manager/fm-properties-window.c')
-rw-r--r--src/file-manager/fm-properties-window.c1938
1 files changed, 1459 insertions, 479 deletions
diff --git a/src/file-manager/fm-properties-window.c b/src/file-manager/fm-properties-window.c
index 0d64711ce..abacf0b65 100644
--- a/src/file-manager/fm-properties-window.c
+++ b/src/file-manager/fm-properties-window.c
@@ -39,6 +39,7 @@
#include <gtk/gtkalignment.h>
#include <gtk/gtkcheckbutton.h>
#include <gtk/gtkdnd.h>
+#include <gtk/gtkeditable.h>
#include <gtk/gtkentry.h>
#include <gtk/gtkfilesel.h>
#include <gtk/gtkhbox.h>
@@ -79,16 +80,15 @@
#include <string.h>
static GHashTable *windows;
-static GHashTable *pending_files;
+static GHashTable *pending_lists;
+
+struct FMPropertiesWindowDetails {
+ GList *original_files;
+ GList *target_files;
-struct FMPropertiesWindowDetails {
- NautilusFile *original_file;
- NautilusFile *target_file;
GtkNotebook *notebook;
GtkWidget *remove_image_button;
- guint file_changed_handler_id;
-
GtkTable *basic_table;
GtkTable *permissions_table;
@@ -106,6 +106,16 @@ struct FMPropertiesWindowDetails {
int first_special_flags_row;
int num_special_flags_rows;
+ GList *emblem_buttons;
+ GHashTable *initial_emblems;
+
+ GList *permission_buttons;
+ GHashTable *initial_permissions;
+
+ GList *value_fields;
+
+ GList *mime_list;
+
gboolean deep_count_finished;
};
@@ -130,9 +140,11 @@ enum {
};
typedef struct {
- NautilusFile *original_file;
- NautilusFile *target_file;
+ GList *original_files;
+ GList *target_files;
FMDirectoryView *directory_view;
+ char *pending_key;
+ GHashTable *pending_files;
} StartupData;
typedef struct {
@@ -160,8 +172,15 @@ static GtkTargetEntry target_table[] = {
#define STANDARD_EMBLEM_HEIGHT 52
#define EMBLEM_LABEL_SPACING 2
-static void create_properties_window_callback (NautilusFile *file,
- gpointer data);
+static void permission_button_update (FMPropertiesWindow *window,
+ GtkToggleButton *button);
+static void value_field_update (FMPropertiesWindow *window,
+ GtkLabel *field);
+static void properties_window_update (FMPropertiesWindow *window,
+ NautilusFile *changed_file);
+
+static void is_directory_ready_callback (NautilusFile *file,
+ gpointer data);
static void cancel_group_change_callback (gpointer callback_data);
static void cancel_owner_change_callback (gpointer callback_data);
static void directory_view_destroyed_callback (FMDirectoryView *view,
@@ -172,11 +191,10 @@ static void set_icon_callback (const char* icon_path,
FMPropertiesWindow *properties_window);
static void remove_image_button_callback (GtkWidget *widget,
FMPropertiesWindow *properties_window);
-static void remove_pending_file (StartupData *data,
+static void remove_pending (StartupData *data,
gboolean cancel_call_when_ready,
gboolean cancel_timed_wait,
gboolean cancel_destroy_handler);
-
static void append_bonobo_pages (FMPropertiesWindow *window);
GNOME_CLASS_BOILERPLATE (FMPropertiesWindow, fm_properties_window,
@@ -210,6 +228,72 @@ file_name_pair_free (FileNamePair *pair)
g_free (pair);
}
+static gboolean
+is_multi_file_window (FMPropertiesWindow *window)
+{
+ GList *l;
+ int count;
+
+ count = 0;
+
+ for (l = window->details->original_files; l != NULL; l = l->next) {
+ if (!nautilus_file_is_gone (NAUTILUS_FILE (l->data))) {
+ count++;
+ if (count > 1) {
+ return TRUE;
+ }
+ }
+ }
+
+ return FALSE;
+}
+
+static NautilusFile *
+get_original_file (FMPropertiesWindow *window)
+{
+ g_return_val_if_fail (!is_multi_file_window (window), NULL);
+
+ return NAUTILUS_FILE (window->details->original_files->data);
+}
+
+static NautilusFile *
+get_target_file_for_original_file (NautilusFile *file)
+{
+ NautilusFile *target_file;
+ char *uri_to_display;
+ NautilusDesktopLink *link;
+
+ target_file = NULL;
+ if (NAUTILUS_IS_DESKTOP_ICON_FILE (file)) {
+ link = nautilus_desktop_icon_file_get_link (NAUTILUS_DESKTOP_ICON_FILE (file));
+
+ /* map to linked URI for these types of links */
+ uri_to_display = nautilus_desktop_link_get_activation_uri (link);
+ if (uri_to_display) {
+ target_file = nautilus_file_get (uri_to_display);
+ g_free (uri_to_display);
+ }
+
+ g_object_unref (link);
+ }
+
+ if (target_file != NULL) {
+ return target_file;
+ }
+
+ /* Ref passed-in file here since we've decided to use it. */
+ nautilus_file_ref (file);
+ return file;
+}
+
+static NautilusFile *
+get_target_file (FMPropertiesWindow *window)
+{
+ g_return_val_if_fail (!is_multi_file_window (window), NULL);
+
+ return NAUTILUS_FILE (window->details->target_files->data);
+}
+
static void
add_prompt (GtkVBox *vbox, const char *prompt_text, gboolean pack_at_start)
{
@@ -236,16 +320,24 @@ add_prompt_and_separator (GtkVBox *vbox, const char *prompt_text)
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 (NautilusFile *file)
{
- g_assert (NAUTILUS_IS_FILE (file));
+ g_return_val_if_fail (file == NULL || NAUTILUS_IS_FILE (file), NULL);
- return nautilus_icon_factory_get_pixbuf_for_file (file, NULL, NAUTILUS_ICON_SIZE_STANDARD);
+ if (file) {
+ return nautilus_icon_factory_get_pixbuf_for_file (file, NULL, NAUTILUS_ICON_SIZE_STANDARD);
+ } else {
+ return nautilus_icon_factory_get_pixbuf_from_name ("gnome-fs-regular",
+ NULL,
+ NAUTILUS_ICON_SIZE_STANDARD,
+ NULL);
+ }
}
+
static void
update_properties_window_icon (GtkImage *image)
{
@@ -263,7 +355,6 @@ update_properties_window_icon (GtkImage *image)
g_object_unref (pixbuf);
}
-
/* utility to test if a uri refers to a local image */
static gboolean
uri_is_local_image (const char *uri)
@@ -286,19 +377,29 @@ uri_is_local_image (const char *uri)
return TRUE;
}
+
static void
reset_icon (FMPropertiesWindow *properties_window)
{
- NautilusFile *file;
-
- file = properties_window->details->original_file;
-
- nautilus_file_set_metadata (file, NAUTILUS_METADATA_KEY_CUSTOM_ICON, NULL, NULL);
- nautilus_file_set_metadata (file, NAUTILUS_METADATA_KEY_ICON_SCALE, NULL, NULL);
+ GList *l;
+
+ for (l = properties_window->details->original_files; l != NULL; l = l->next) {
+ NautilusFile *file;
+
+ file = NAUTILUS_FILE (l->data);
+
+ nautilus_file_set_metadata (file,
+ NAUTILUS_METADATA_KEY_ICON_SCALE,
+ NULL, NULL);
+ nautilus_file_set_metadata (file,
+ NAUTILUS_METADATA_KEY_CUSTOM_ICON,
+ NULL, NULL);
+ }
gtk_widget_set_sensitive (properties_window->details->remove_image_button, FALSE);
}
+
static void
fm_properties_window_drag_data_received (GtkWidget *widget, GdkDragContext *context,
int x, int y,
@@ -372,81 +473,118 @@ create_image_widget_for_file (NautilusFile *file)
g_signal_connect (image, "drag_data_received",
G_CALLBACK (fm_properties_window_drag_data_received), NULL);
-
gtk_image_set_from_pixbuf (GTK_IMAGE (image), pixbuf);
g_object_unref (pixbuf);
- nautilus_file_ref (file);
- g_object_set_data_full (G_OBJECT (image), "nautilus_file",
- file, (GDestroyNotify) nautilus_file_unref);
+ if (file) {
+ nautilus_file_ref (file);
+ g_object_set_data_full (G_OBJECT (image), "nautilus_file",
+ file, (GDestroyNotify) nautilus_file_unref);
+
+ /* Name changes can also change icon (since name is determined by MIME type) */
+ g_signal_connect_object (file, "changed",
+ G_CALLBACK (update_properties_window_icon),
+ image, G_CONNECT_SWAPPED);
+ }
+
/* React to icon theme changes. */
g_signal_connect_object (nautilus_icon_factory_get (),
"icons_changed",
G_CALLBACK (update_properties_window_icon),
image, G_CONNECT_SWAPPED);
- /* Name changes can also change icon (since name is determined by MIME type) */
- g_signal_connect_object (file, "changed",
- G_CALLBACK (update_properties_window_icon),
- image, G_CONNECT_SWAPPED);
return image;
}
static void
-name_field_update_to_match_file (NautilusEntry *name_field)
+update_name_field (FMPropertiesWindow *window)
{
NautilusFile *file;
const char *original_name;
char *current_name, *displayed_name;
- file = g_object_get_data (G_OBJECT (name_field), "nautilus_file");
+ if (is_multi_file_window (window)) {
+ /* Multifile property dialog, show all names */
+ GString *str;
+ char *name;
+ gboolean first;
+ GList *l;
+
+ str = g_string_new ("");
- if (file == NULL || nautilus_file_is_gone (file)) {
- gtk_widget_set_sensitive (GTK_WIDGET (name_field), FALSE);
- gtk_entry_set_text (GTK_ENTRY (name_field), "");
- return;
- }
+ first = TRUE;
- original_name = (const char *) g_object_get_data (G_OBJECT (name_field),
- "original_name");
+ for (l = window->details->original_files; l != NULL; l = l->next) {
+ file = NAUTILUS_FILE (l->data);
- /* If the file name has changed since the original name was stored,
- * update the text in the text field, possibly (deliberately) clobbering
- * an edit in progress. If the name hasn't changed (but some other
- * aspect of the file might have), then don't clobber changes.
- */
- current_name = nautilus_file_get_display_name (file);
- if (original_name == NULL ||
- eel_strcmp (original_name, current_name) != 0) {
- g_object_set_data_full (G_OBJECT (name_field),
- "original_name",
- current_name,
- g_free);
-
- /* Only reset the text if it's different from what is
- * currently showing. This causes minimal ripples (e.g.
- * selection change).
- */
- displayed_name = gtk_editable_get_chars (GTK_EDITABLE (name_field), 0, -1);
- if (strcmp (displayed_name, current_name) != 0) {
- gtk_entry_set_text (GTK_ENTRY (name_field), current_name);
+ if (!nautilus_file_is_gone (file)) {
+ if (!first) {
+ g_string_append (str, ", ");
+ }
+ first = FALSE;
+
+ name = nautilus_file_get_display_name (file);
+ g_string_append (str, name);
+ g_free (name);
+ }
}
- g_free (displayed_name);
+ gtk_entry_set_text (GTK_ENTRY (window->details->name_field),
+ str->str);
+ g_string_free (str, TRUE);
+
+ gtk_editable_set_editable (GTK_EDITABLE (window->details->name_field),
+ FALSE);
} else {
- g_free (current_name);
- }
+ NautilusFile *file;
- /*
- * The UI would look better here if the name were just drawn as
- * a plain label in the case where it's not editable, with no
- * border at all. That doesn't seem to be possible with GtkEntry,
- * so we'd have to swap out the widget to achieve it. I don't
- * care enough to change this now.
- */
- gtk_widget_set_sensitive (GTK_WIDGET (name_field),
- nautilus_file_can_rename (file));
+ file = get_original_file (window);
+
+ if (file == NULL || nautilus_file_is_gone (file)) {
+ gtk_entry_set_text (GTK_ENTRY (window->details->name_field), "");
+ return;
+ }
+
+ original_name = (const char *) g_object_get_data (G_OBJECT (window->details->name_field),
+ "original_name");
+
+ /* If the file name has changed since the original name was stored,
+ * update the text in the text field, possibly (deliberately) clobbering
+ * an edit in progress. If the name hasn't changed (but some other
+ * aspect of the file might have), then don't clobber changes.
+ */
+ current_name = nautilus_file_get_display_name (file);
+ if (original_name == NULL ||
+ eel_strcmp (original_name, current_name) != 0) {
+ g_object_set_data_full (G_OBJECT (window->details->name_field),
+ "original_name",
+ current_name,
+ g_free);
+
+ /* Only reset the text if it's different from what is
+ * currently showing. This causes minimal ripples (e.g.
+ * selection change).
+ */
+ displayed_name = gtk_editable_get_chars (GTK_EDITABLE (window->details->name_field), 0, -1);
+ if (strcmp (displayed_name, current_name) != 0) {
+ gtk_entry_set_text (GTK_ENTRY (window->details->name_field), current_name);
+ }
+ g_free (displayed_name);
+ } else {
+ g_free (current_name);
+ }
+
+ /*
+ * The UI would look better here if the name were just drawn as
+ * a plain label in the case where it's not editable, with no
+ * border at all. That doesn't seem to be possible with GtkEntry,
+ * so we'd have to swap out the widget to achieve it. I don't
+ * care enough to change this now.
+ */
+ gtk_widget_set_sensitive (GTK_WIDGET (window->details->name_field),
+ nautilus_file_can_rename (file));
+ }
}
static void
@@ -457,6 +595,11 @@ name_field_restore_original_name (NautilusEntry *name_field)
original_name = (const char *) g_object_get_data (G_OBJECT (name_field),
"original_name");
+
+ if (!original_name) {
+ return;
+ }
+
displayed_name = gtk_editable_get_chars (GTK_EDITABLE (name_field), 0, -1);
if (strcmp (original_name, displayed_name) != 0) {
@@ -503,11 +646,14 @@ name_field_done_editing (NautilusEntry *name_field, FMPropertiesWindow *window)
NautilusFile *file;
char *new_name;
- g_assert (NAUTILUS_IS_ENTRY (name_field));
+ g_return_if_fail (NAUTILUS_IS_ENTRY (name_field));
- file = g_object_get_data (G_OBJECT (name_field), "nautilus_file");
+ /* Don't apply if the dialog has more than one file */
+ if (is_multi_file_window (window)) {
+ return;
+ }
- g_assert (NAUTILUS_IS_FILE (file));
+ file = get_original_file (window);
/* This gets called when the window is closed, which might be
* caused by the file having been deleted.
@@ -557,74 +703,184 @@ name_field_activate (NautilusEntry *name_field, gpointer callback_data)
nautilus_entry_select_all_at_idle (name_field);
}
-static void
-property_button_update (GtkToggleButton *button)
+static gboolean
+file_has_keyword (NautilusFile *file, const char *keyword)
{
- NautilusFile *file;
- char *name;
GList *keywords, *word;
- file = g_object_get_data (G_OBJECT (button), "nautilus_file");
- name = g_object_get_data (G_OBJECT (button), "nautilus_property_name");
+ keywords = nautilus_file_get_keywords (file);
+ word = g_list_find_custom (keywords, keyword, (GCompareFunc) strcmp);
+ eel_g_list_free_deep (keywords);
+
+ return (word != NULL);
+}
- /* Handle the case where there's nothing to toggle. */
- if (file == NULL || nautilus_file_is_gone (file) || name == NULL) {
- gtk_widget_set_sensitive (GTK_WIDGET (button), FALSE);
- gtk_toggle_button_set_active (button, FALSE);
- return;
+static void
+get_initial_emblem_state (FMPropertiesWindow *window,
+ const char *name,
+ GList **on,
+ GList **off)
+{
+ GList *l;
+
+ *on = NULL;
+ *off = NULL;
+
+ for (l = window->details->original_files; l != NULL; l = l->next) {
+ GList *initial_emblems;
+
+ initial_emblems = g_hash_table_lookup (window->details->initial_emblems,
+ l->data);
+
+ if (g_list_find_custom (initial_emblems, name, (GCompareFunc) strcmp)) {
+ *on = g_list_prepend (*on, l->data);
+ } else {
+ *off = g_list_prepend (*off, l->data);
+ }
}
-
- /* Check and see if it's in there. */
- keywords = nautilus_file_get_keywords (file);
- word = g_list_find_custom (keywords, name, (GCompareFunc) strcmp);
- gtk_toggle_button_set_active (button, word != NULL);
}
static void
-property_button_toggled (GtkToggleButton *button)
+emblem_button_toggled (GtkToggleButton *button,
+ FMPropertiesWindow *window)
{
- NautilusFile *file;
+ GList *l;
+ GList *keywords;
+ GList *word;
char *name;
- GList *keywords, *word;
-
- file = g_object_get_data (G_OBJECT (button), "nautilus_file");
- name = g_object_get_data (G_OBJECT (button), "nautilus_property_name");
-
- /* Handle the case where there's nothing to toggle. */
- if (file == NULL || nautilus_file_is_gone (file) || name == NULL) {
- return;
+ GList *files_on;
+ GList *files_off;
+
+ name = g_object_get_data (G_OBJECT (button), "nautilus_emblem_name");
+
+ files_on = NULL;
+ files_off = NULL;
+ if (gtk_toggle_button_get_active (button)
+ && !gtk_toggle_button_get_inconsistent (button)) {
+ /* Go to the initial state unless the initial state was
+ consistent */
+ get_initial_emblem_state (window, name,
+ &files_on, &files_off);
+
+ if (!(files_on && files_off)) {
+ g_list_free (files_on);
+ g_list_free (files_off);
+ files_on = g_list_copy (window->details->original_files);
+ files_off = NULL;
+ }
+ } else if (gtk_toggle_button_get_inconsistent (button)
+ && !gtk_toggle_button_get_active (button)) {
+ files_on = g_list_copy (window->details->original_files);
+ files_off = NULL;
+ } else {
+ files_off = g_list_copy (window->details->original_files);
+ files_on = NULL;
}
+
+ g_signal_handlers_block_by_func (G_OBJECT (button),
+ G_CALLBACK (emblem_button_toggled),
+ window);
+
+ gtk_toggle_button_set_active (button, files_on != NULL);
+ gtk_toggle_button_set_inconsistent (button, files_on && files_off);
- /* Check and see if it's already there. */
- keywords = nautilus_file_get_keywords (file);
- word = g_list_find_custom (keywords, name, (GCompareFunc) strcmp);
- if (gtk_toggle_button_get_active (button)) {
- if (word == NULL) {
+ g_signal_handlers_unblock_by_func (G_OBJECT (button),
+ G_CALLBACK (emblem_button_toggled),
+ window);
+
+ for (l = files_on; l != NULL; l = l->next) {
+ NautilusFile *file;
+
+ file = NAUTILUS_FILE (l->data);
+
+ keywords = nautilus_file_get_keywords (file);
+
+ word = g_list_find_custom (keywords, name, (GCompareFunc)strcmp);
+ if (!word) {
keywords = g_list_prepend (keywords, g_strdup (name));
}
- } else {
- if (word != NULL) {
+ nautilus_file_set_keywords (file, keywords);
+ eel_g_list_free_deep (keywords);
+ }
+
+ for (l = files_off; l != NULL; l = l->next) {
+ NautilusFile *file;
+
+ file = NAUTILUS_FILE (l->data);
+
+ keywords = nautilus_file_get_keywords (file);
+
+ word = g_list_find_custom (keywords, name, (GCompareFunc)strcmp);
+ if (word) {
keywords = g_list_remove_link (keywords, word);
eel_g_list_free_deep (word);
}
+ nautilus_file_set_keywords (file, keywords);
+ eel_g_list_free_deep (keywords);
+ }
+
+ g_list_free (files_on);
+ g_list_free (files_off);
+}
+
+static void
+emblem_button_update (FMPropertiesWindow *window,
+ GtkToggleButton *button)
+{
+ GList *l;
+ char *name;
+ gboolean all_set;
+ gboolean all_unset;
+
+ name = g_object_get_data (G_OBJECT (button), "nautilus_emblem_name");
+
+ all_set = TRUE;
+ all_unset = TRUE;
+ for (l = window->details->original_files; l != NULL; l = l->next) {
+ gboolean has_keyword;
+ NautilusFile *file;
+
+ file = NAUTILUS_FILE (l->data);
+
+ has_keyword = file_has_keyword (file, name);
+
+ if (has_keyword) {
+ all_unset = FALSE;
+ } else {
+ all_set = FALSE;
+ }
}
- nautilus_file_set_keywords (file, keywords);
- eel_g_list_free_deep (keywords);
+
+ g_signal_handlers_block_by_func (G_OBJECT (button),
+ G_CALLBACK (emblem_button_toggled),
+ window);
+
+ gtk_toggle_button_set_active (button, !all_unset);
+ gtk_toggle_button_set_inconsistent (button, !all_unset && !all_set);
+
+ g_signal_handlers_unblock_by_func (G_OBJECT (button),
+ G_CALLBACK (emblem_button_toggled),
+ window);
+
}
static void
-update_properties_window_title (GtkWindow *window, NautilusFile *file)
+update_properties_window_title (FMPropertiesWindow *window)
{
char *name, *title;
- g_assert (NAUTILUS_IS_FILE (file));
- g_assert (GTK_IS_WINDOW (window));
+ g_return_if_fail (GTK_IS_WINDOW (window));
- name = nautilus_file_get_display_name (file);
- title = g_strdup_printf (_("%s Properties"), name);
- gtk_window_set_title (window, title);
+ if (is_multi_file_window (window)) {
+ title = g_strdup_printf (_("Properties"));
+ } else {
+ name = nautilus_file_get_display_name (get_original_file (window));
+ title = g_strdup_printf (_("%s Properties"), name);
+ g_free (name);
+ }
+
+ gtk_window_set_title (GTK_WINDOW (window), title);
- g_free (name);
g_free (title);
}
@@ -659,54 +915,247 @@ refresh_bonobo_pages (FMPropertiesWindow *window)
}
static void
-properties_window_file_changed_callback (FMPropertiesWindow *window, NautilusFile *file)
+remove_from_dialog (FMPropertiesWindow *window,
+ NautilusFile *file)
{
- g_assert (GTK_IS_WINDOW (window));
- g_assert (NAUTILUS_IS_FILE (file));
+ int index;
+ GList *original_link;
+ GList *target_link;
+ NautilusFile *original_file;
+ NautilusFile *target_file;
- if (nautilus_file_is_gone (file)) {
- gtk_widget_destroy (GTK_WIDGET (window));
+ index = g_list_index (window->details->target_files, file);
+ if (index == -1) {
+ index = g_list_index (window->details->original_files, file);
+ g_return_if_fail (index != -1);
+ }
+
+ original_link = g_list_nth (window->details->original_files, index);
+ target_link = g_list_nth (window->details->target_files, index);
+
+ g_return_if_fail (original_link && target_link);
+
+ original_file = NAUTILUS_FILE (original_link->data);
+ target_file = NAUTILUS_FILE (target_link->data);
+
+ window->details->original_files = g_list_remove_link (window->details->original_files, original_link);
+ g_list_free (original_link);
+
+ window->details->target_files = g_list_remove_link (window->details->original_files, target_link);
+ g_list_free (target_link);
+
+ g_hash_table_remove (window->details->initial_emblems, original_file);
+ g_hash_table_remove (window->details->initial_permissions, target_file);
+
+ g_signal_handlers_disconnect_by_func (original_file,
+ G_CALLBACK (properties_window_update),
+ window);
+ g_signal_handlers_disconnect_by_func (target_file,
+ G_CALLBACK (properties_window_update),
+ window);
+
+ nautilus_file_monitor_remove (original_file, window);
+ nautilus_file_monitor_remove (target_file, window);
+
+ nautilus_file_unref (original_file);
+ nautilus_file_unref (target_file);
+
+}
+
+static gboolean
+mime_list_equal (GList *a, GList *b)
+{
+ while (a && b) {
+ if (strcmp (a->data, b->data)) {
+ return FALSE;
+ }
+ a = a->next;
+ b = b->next;
+ }
+
+ return (a == b);
+}
+
+static GList *
+get_mime_list (FMPropertiesWindow *window)
+{
+ GList *ret;
+ GList *l;
+
+ ret = NULL;
+ for (l = window->details->target_files; l != NULL; l = l->next) {
+ ret = g_list_append (ret, nautilus_file_get_mime_type (NAUTILUS_FILE (l->data)));
+ }
+ ret = g_list_reverse (ret);
+ return ret;
+}
+
+static void
+properties_window_update (FMPropertiesWindow *window,
+ NautilusFile *changed_file)
+{
+ GList *l;
+ GList *mime_list;
+
+ if (changed_file && nautilus_file_is_gone (changed_file)) {
+ remove_from_dialog (window, changed_file);
+ changed_file = NULL;
+
+ /* Remove the file from the property dialog */
+ if (window->details->original_files == NULL) {
+ gtk_widget_destroy (GTK_WIDGET (window));
+ return;
+ }
+
+ }
+
+ if (!changed_file
+ || g_list_find (window->details->original_files, changed_file)) {
+
+ update_properties_window_title (window);
+
+ update_name_field (window);
+
+ for (l = window->details->emblem_buttons; l != NULL; l = l->next) {
+ emblem_button_update (window, GTK_TOGGLE_BUTTON (l->data));
+ }
+
+ /* If any of the value fields start to depend on the original
+ * value, value_field_updates should be added here */
+ }
+
+ if (!changed_file
+ || g_list_find (window->details->target_files, changed_file)) {
+ for (l = window->details->permission_buttons; l != NULL; l = l->next) {
+ permission_button_update (window, GTK_TOGGLE_BUTTON (l->data));
+ }
+
+ for (l = window->details->value_fields; l != NULL; l = l->next) {
+ value_field_update (window, GTK_LABEL (l->data));
+ }
+ }
+
+ mime_list = get_mime_list (window);
+
+ if (!window->details->mime_list) {
+ window->details->mime_list = mime_list;
} else {
- char *orig_mime_type;
- char *new_mime_type;
+ if (!mime_list_equal (window->details->mime_list, mime_list)) {
+ refresh_bonobo_pages (window);
+ }
+
+ eel_g_list_free_deep (window->details->mime_list);
+ window->details->mime_list = mime_list;
+ }
+}
+
+static gboolean
+file_list_attributes_identical (GList *file_list, const char *attribute_name)
+{
+ gboolean identical;
+ char *first_attr;
+ GList *l;
+
+ first_attr = NULL;
+ identical = TRUE;
+
+ for (l = file_list; l != NULL; l = l->next) {
+ NautilusFile *file;
- orig_mime_type = nautilus_file_get_mime_type
- (window->details->target_file);
- nautilus_file_unref (window->details->target_file);
+ file = NAUTILUS_FILE (l->data);
+
+ if (nautilus_file_is_gone (file)) {
+ continue;
+ }
+
+ if (first_attr == NULL) {
+ first_attr = nautilus_file_get_string_attribute_with_default (file, attribute_name);
+ } else {
+ char *attr;
+ attr = nautilus_file_get_string_attribute_with_default (file, attribute_name);
+ if (strcmp (attr, first_attr)) {
+ identical = FALSE;
+ g_free (attr);
+ break;
+ }
+ g_free (attr);
+ }
+ }
- window->details->target_file = nautilus_file_ref (file);
+ g_free (first_attr);
+ return identical;
+}
- update_properties_window_title (GTK_WINDOW (window), file);
+static char *
+file_list_get_string_attribute (GList *file_list,
+ const char *attribute_name,
+ const char *inconsistent_value)
+{
+ if (file_list_attributes_identical (file_list, attribute_name)) {
+ GList *l;
+
+ for (l = file_list; l != NULL; l = l->next) {
+ NautilusFile *file;
+
+ file = NAUTILUS_FILE (l->data);
+ if (!nautilus_file_is_gone (file)) {
+ return nautilus_file_get_string_attribute_with_default
+ (file,
+ attribute_name);
+ }
+ }
+ return g_strdup (_("unknown"));
+ } else {
+ return g_strdup (inconsistent_value);
+ }
+}
- new_mime_type = nautilus_file_get_mime_type
- (window->details->target_file);
- if (strcmp (orig_mime_type, new_mime_type) != 0) {
- refresh_bonobo_pages (window);
+static gboolean
+file_list_all_local (GList *file_list)
+{
+ GList *l;
+ for (l = file_list; l != NULL; l = l->next) {
+ if (!nautilus_file_is_local (NAUTILUS_FILE (l->data))) {
+ return FALSE;
}
+ }
+ return TRUE;
+}
- g_free (orig_mime_type);
- g_free (new_mime_type);
+static gboolean
+file_list_all_directories (GList *file_list)
+{
+ GList *l;
+ for (l = file_list; l != NULL; l = l->next) {
+ if (!nautilus_file_is_directory (NAUTILUS_FILE (l->data))) {
+ return FALSE;
+ }
}
+ return TRUE;
}
static void
value_field_update_internal (GtkLabel *label,
- NautilusFile *file,
+ GList *file_list,
gboolean ellipsize_text)
{
const char *attribute_name;
char *attribute_value;
+ char *inconsistent_string;
g_assert (GTK_IS_LABEL (label));
- g_assert (NAUTILUS_IS_FILE (file));
g_assert (!ellipsize_text || EEL_IS_ELLIPSIZING_LABEL (label));
attribute_name = g_object_get_data (G_OBJECT (label), "file_attribute");
- attribute_value = nautilus_file_get_string_attribute_with_default (file, attribute_name);
+ inconsistent_string = g_object_get_data (G_OBJECT (label), "inconsistent_string");
+ attribute_value = file_list_get_string_attribute (file_list,
+ attribute_name,
+ inconsistent_string);
if (ellipsize_text) {
- eel_ellipsizing_label_set_text (EEL_ELLIPSIZING_LABEL (label), attribute_value);
+ eel_ellipsizing_label_set_text (EEL_ELLIPSIZING_LABEL (label),
+ attribute_value);
} else {
gtk_label_set_text (label, attribute_value);
}
@@ -714,15 +1163,19 @@ value_field_update_internal (GtkLabel *label,
}
static void
-value_field_update (GtkLabel *label, NautilusFile *file)
+value_field_update (FMPropertiesWindow *window, GtkLabel *label)
{
- value_field_update_internal (label, file, FALSE);
-}
+ gboolean ellipsize_text;
+ gboolean use_original;
-static void
-ellipsizing_value_field_update (GtkLabel *label, NautilusFile *file)
-{
- value_field_update_internal (label, file, TRUE);
+ ellipsize_text = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (label), "ellipsize_text"));
+ use_original = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (label), "use_original"));
+
+ value_field_update_internal (label,
+ (use_original ?
+ window->details->original_files :
+ window->details->target_files),
+ ellipsize_text);
}
static GtkLabel *
@@ -786,11 +1239,13 @@ attach_ellipsizing_value_label (GtkTable *table,
}
static void
-attach_value_field_internal (GtkTable *table,
+attach_value_field_internal (FMPropertiesWindow *window,
+ GtkTable *table,
int row,
int column,
- NautilusFile *file,
const char *file_attribute_name,
+ const char *inconsistent_string,
+ gboolean show_original,
gboolean ellipsize_text)
{
GtkLabel *value_field;
@@ -801,43 +1256,52 @@ attach_value_field_internal (GtkTable *table,
value_field = attach_value_label (table, row, column, "");
}
- /* Stash a copy of the file attribute name in this field for the callback's sake. */
+ /* Stash a copy of the file attribute name in this field for the callback's sake. */
g_object_set_data_full (G_OBJECT (value_field), "file_attribute",
g_strdup (file_attribute_name), g_free);
- /* Fill in the value. */
- if (ellipsize_text) {
- ellipsizing_value_field_update (value_field, file);
- } else {
- value_field_update (value_field, file);
- }
+ g_object_set_data_full (G_OBJECT (value_field), "inconsistent_string",
+ g_strdup (inconsistent_string), g_free);
- /* Connect to signal to update value when file changes. */
- g_signal_connect_object (file, "changed",
- ellipsize_text
- ? G_CALLBACK (ellipsizing_value_field_update)
- : G_CALLBACK (value_field_update),
- value_field, G_CONNECT_SWAPPED);
+ 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));
+
+ window->details->value_fields = g_list_prepend (window->details->value_fields,
+ value_field);
}
static void
-attach_value_field (GtkTable *table,
+attach_value_field (FMPropertiesWindow *window,
+ GtkTable *table,
int row,
int column,
- NautilusFile *file,
- const char *file_attribute_name)
+ const char *file_attribute_name,
+ const char *inconsistent_string,
+ gboolean show_original)
{
- attach_value_field_internal (table, row, column, file, file_attribute_name, FALSE);
+ attach_value_field_internal (window,
+ table, row, column,
+ file_attribute_name,
+ inconsistent_string,
+ show_original,
+ FALSE);
}
static void
-attach_ellipsizing_value_field (GtkTable *table,
+attach_ellipsizing_value_field (FMPropertiesWindow *window,
+ GtkTable *table,
int row,
int column,
- NautilusFile *file,
- const char *file_attribute_name)
+ const char *file_attribute_name,
+ const char *inconsistent_string,
+ gboolean show_original)
{
- attach_value_field_internal (table, row, column, file, file_attribute_name, TRUE);
+ attach_value_field_internal (window,
+ table, row, column,
+ file_attribute_name,
+ inconsistent_string,
+ show_original,
+ TRUE);
}
static void
@@ -1173,8 +1637,8 @@ append_separator (GtkTable *table)
GTK_FILL, 0,
0, 0);
return separator;
-}
-
+}
+
static void
directory_contents_value_field_update (FMPropertiesWindow *window)
{
@@ -1191,7 +1655,13 @@ directory_contents_value_field_update (FMPropertiesWindow *window)
g_assert (FM_IS_PROPERTIES_WINDOW (window));
- file = window->details->target_file;
+ /* For right now this will only work on single-file property
+ * dialogs */
+ if (is_multi_file_window (window)) {
+ return ;
+ }
+
+ file = get_target_file (window);
g_assert (nautilus_file_is_directory (file) || nautilus_file_is_gone (file));
status = nautilus_file_get_deep_counts (file,
@@ -1303,20 +1773,25 @@ attach_directory_contents_value_field (FMPropertiesWindow *window,
gtk_label_set_line_wrap (value_field, TRUE);
+
+ /* For right now, this will only be called for single-file
+ * property dialogs */
+ g_return_val_if_fail (!is_multi_file_window (window), value_field);
+
/* Always recompute from scratch when the window is shown. */
- nautilus_file_recompute_deep_counts (window->details->target_file);
+ nautilus_file_recompute_deep_counts (get_target_file (window));
/* Fill in the initial value. */
directory_contents_value_field_update (window);
/* Connect to signal to update value when file changes. */
- g_signal_connect_object (window->details->target_file,
+ g_signal_connect_object (get_target_file (window),
"updated_deep_count_in_progress",
G_CALLBACK (schedule_directory_contents_update),
window, G_CONNECT_SWAPPED);
return value_field;
-}
+}
static GtkLabel *
attach_title_field (GtkTable *table,
@@ -1343,29 +1818,39 @@ append_title_field (GtkTable *table, const char *title, GtkLabel **label)
}
static guint
-append_title_value_pair (GtkTable *table,
+append_title_value_pair (FMPropertiesWindow *window,
+ GtkTable *table,
const char *title,
- NautilusFile *file,
- const char *file_attribute_name)
+ const char *file_attribute_name,
+ const char *inconsistent_state,
+ gboolean show_original)
{
guint last_row;
last_row = append_title_field (table, title, NULL);
- attach_value_field (table, last_row, VALUE_COLUMN, file, file_attribute_name);
+ attach_value_field (window, table, last_row, VALUE_COLUMN,
+ file_attribute_name,
+ inconsistent_state,
+ show_original);
return last_row;
}
static guint
-append_title_and_ellipsizing_value (GtkTable *table,
+append_title_and_ellipsizing_value (FMPropertiesWindow *window,
+ GtkTable *table,
const char *title,
- NautilusFile *file,
- const char *file_attribute_name)
+ const char *file_attribute_name,
+ const char *inconsistent_state,
+ gboolean show_original)
{
guint last_row;
last_row = append_title_field (table, title, NULL);
- attach_ellipsizing_value_field (table, last_row, VALUE_COLUMN, file, file_attribute_name);
+ attach_ellipsizing_value_field (window, table, last_row, VALUE_COLUMN,
+ file_attribute_name,
+ inconsistent_state,
+ show_original);
return last_row;
}
@@ -1396,9 +1881,17 @@ update_visibility_of_table_rows (GtkTable *table,
static void
update_visibility_of_item_count_fields (FMPropertiesWindow *window)
{
+ gboolean should_show_count;
+
+ if (is_multi_file_window (window)) {
+ should_show_count = FALSE;
+ } else {
+ should_show_count = nautilus_file_should_show_directory_item_count (get_target_file (window));
+ }
+
update_visibility_of_table_rows
(window->details->basic_table,
- nautilus_file_should_show_directory_item_count (window->details->target_file),
+ should_show_count,
window->details->directory_contents_row,
1,
window->details->directory_contents_widgets);
@@ -1530,7 +2023,8 @@ should_show_custom_icon_buttons (FMPropertiesWindow *window)
* we shouldn't pretend that they work by showing them here.
* When bug 5642 is fixed we can remove this case.
*/
- if (is_merged_trash_directory (window->details->target_file)) {
+ if (!is_multi_file_window (window)
+ && is_merged_trash_directory (get_target_file (window))) {
return FALSE;
}
@@ -1541,10 +2035,12 @@ static gboolean
should_show_file_type (FMPropertiesWindow *window)
{
/* The trash on the desktop is one-of-a-kind */
- if (is_merged_trash_directory (window->details->target_file)) {
+ if (!is_multi_file_window (window)
+ && is_merged_trash_directory (get_target_file (window))) {
return FALSE;
}
+
return TRUE;
}
@@ -1555,7 +2051,7 @@ should_show_accessed_date (FMPropertiesWindow *window)
* day decide that it is useful, we should separately
* consider whether it's useful for "trash:".
*/
- if (nautilus_file_is_directory (window->details->target_file)) {
+ if (file_list_all_directories (window->details->target_files)) {
return FALSE;
}
@@ -1570,7 +2066,7 @@ should_show_mime_type (FMPropertiesWindow *window)
* trash directory, but doesn't. I could trivially fix this
* with a check for is_merged_trash_directory here instead.
*/
- if (nautilus_file_is_directory (window->details->target_file)) {
+ if (file_list_all_directories (window->details->target_files)) {
return FALSE;
}
@@ -1580,7 +2076,8 @@ should_show_mime_type (FMPropertiesWindow *window)
static gboolean
should_show_link_target (FMPropertiesWindow *window)
{
- if (nautilus_file_is_symbolic_link (window->details->target_file)) {
+ if (!is_multi_file_window (window)
+ && nautilus_file_is_symbolic_link (get_target_file (window))) {
return TRUE;
}
@@ -1590,8 +2087,8 @@ should_show_link_target (FMPropertiesWindow *window)
static gboolean
should_show_free_space (FMPropertiesWindow *window)
{
- if (nautilus_file_is_local (window->details->target_file)
- && nautilus_file_is_directory (window->details->target_file)) {
+ if (file_list_all_local (window->details->target_files)
+ && file_list_all_directories (window->details->target_files)) {
return TRUE;
}
@@ -1603,14 +2100,11 @@ create_basic_page (FMPropertiesWindow *window)
{
GtkTable *table;
GtkWidget *container;
- GtkWidget *icon_pixmap_widget, *icon_aligner, *name_field;
- GtkWidget *button_box, *temp_button;
- char *image_uri;
- NautilusFile *target_file, *original_file;
- GtkWidget *hbox, *name_label;
+ GtkWidget *name_field;
+ GtkWidget *icon_aligner;
+ GtkWidget *icon_pixmap_widget;
- target_file = window->details->target_file;
- original_file = window->details->original_file;
+ GtkWidget *hbox, *name_label;
create_page_with_table_in_vbox (window->details->notebook,
_("Basic"),
@@ -1630,17 +2124,25 @@ create_basic_page (FMPropertiesWindow *window)
0, 0,
0, 0);
- icon_pixmap_widget = create_image_widget_for_file (original_file);
+ if (is_multi_file_window (window)) {
+ icon_pixmap_widget = create_image_widget_for_file (NULL);
+ } else {
+ icon_pixmap_widget = create_image_widget_for_file (get_original_file (window));
+ }
gtk_widget_show (icon_pixmap_widget);
icon_aligner = gtk_alignment_new (1, 0.5, 0, 0);
gtk_widget_show (icon_aligner);
-
+
gtk_container_add (GTK_CONTAINER (icon_aligner), icon_pixmap_widget);
gtk_box_pack_start (GTK_BOX (hbox), icon_aligner, TRUE, TRUE, 0);
/* Name label */
- name_label = gtk_label_new_with_mnemonic (_("_Name:"));
+ if (is_multi_file_window (window)) {
+ name_label = gtk_label_new_with_mnemonic (_("_Names:"));
+ } else {
+ name_label = gtk_label_new_with_mnemonic (_("_Name:"));
+ }
eel_gtk_label_make_bold (GTK_LABEL (name_label));
gtk_widget_show (name_label);
gtk_box_pack_end (GTK_BOX (hbox), name_label, FALSE, FALSE, 0);
@@ -1658,13 +2160,8 @@ create_basic_page (FMPropertiesWindow *window)
0, 0);
gtk_label_set_mnemonic_widget (GTK_LABEL (name_label), name_field);
- /* Attach parameters and signal handler. */
- nautilus_file_ref (original_file);
- g_object_set_data_full (G_OBJECT (name_field),"nautilus_file",
- original_file, (GDestroyNotify) nautilus_file_unref);
-
/* Update name field initially before hooking up changed signal. */
- name_field_update_to_match_file (NAUTILUS_ENTRY (name_field));
+ update_name_field (window);
/* FIXME bugzilla.gnome.org 42151:
* With this (and one place elsewhere in this file, not sure which is the
@@ -1690,44 +2187,80 @@ create_basic_page (FMPropertiesWindow *window)
nautilus_entry_select_all (NAUTILUS_ENTRY (name_field));
gtk_widget_grab_focus (GTK_WIDGET (name_field));
}
-
- /* React to name changes from elsewhere. */
- g_signal_connect_object (target_file,
- "changed",
- G_CALLBACK (name_field_update_to_match_file),
- name_field, G_CONNECT_SWAPPED);
-
+
if (should_show_file_type (window)) {
- append_title_value_pair (table, _("Type:"), target_file, "type");
+ append_title_value_pair (window,
+ table, _("Type:"),
+ "type",
+ _("--"),
+ FALSE);
}
- if (nautilus_file_is_directory (target_file)) {
+
+ if (is_multi_file_window (window)) {
+ /* FIXME: append a total size field here */
+#if 0
+ append_total_size_field (window, table);
+#endif
+ } else if (nautilus_file_is_directory (get_target_file (window))) {
append_directory_contents_fields (window, table);
} else {
- append_title_value_pair (table, _("Size:"), target_file, "size");
+ append_title_value_pair (window, table, _("Size:"),
+ "size",
+ _("--"),
+ FALSE);
}
- append_title_and_ellipsizing_value (table, _("Location:"), target_file, "where");
+
+ append_title_and_ellipsizing_value (window, table, _("Location:"),
+ "where",
+ _("--"),
+ FALSE);
if (should_show_free_space (window)) {
- append_title_and_ellipsizing_value (table, _("Volume:"), target_file, "volume");
- append_title_value_pair (table, _("Free space:"), target_file, "free_space");
+ append_title_and_ellipsizing_value (window, table,
+ _("Volume:"),
+ "volume",
+ _("--"),
+ FALSE);
+ append_title_value_pair (window, table, _("Free space:"),
+ "free_space",
+ _("--"),
+ FALSE);
}
+
if (should_show_link_target (window)) {
- append_title_and_ellipsizing_value (table, _("Link target:"), target_file, "link_target");
+ append_title_and_ellipsizing_value (window, table,
+ _("Link target:"),
+ "link_target",
+ _("--"),
+ FALSE);
}
if (should_show_mime_type (window)) {
- append_title_value_pair (table, _("MIME type:"), target_file, "mime_type");
+ append_title_value_pair (window, table, _("MIME type:"),
+ "mime_type",
+ _("--"),
+ FALSE);
}
/* Blank title ensures standard row height */
append_title_field (table, "", NULL);
- append_title_value_pair (table, _("Modified:"), target_file, "date_modified");
-
+ append_title_value_pair (window, table, _("Modified:"),
+ "date_modified",
+ _("--"),
+ FALSE);
+
if (should_show_accessed_date (window)) {
- append_title_value_pair (table, _("Accessed:"), target_file, "date_accessed");
+ append_title_value_pair (window, table, _("Accessed:"),
+ "date_accessed",
+ _("--"),
+ FALSE);
}
if (should_show_custom_icon_buttons (window)) {
+ GtkWidget *button_box;
+ GtkWidget *temp_button;
+ GList *l;
+
/* add command buttons for setting and clearing custom icons */
button_box = gtk_hbox_new (FALSE, 0);
gtk_widget_show (button_box);
@@ -1748,11 +2281,43 @@ create_basic_page (FMPropertiesWindow *window)
window->details->remove_image_button = temp_button;
/* de-sensitize the remove button if there isn't a custom image */
- image_uri = nautilus_file_get_metadata
- (original_file, NAUTILUS_METADATA_KEY_CUSTOM_ICON, NULL);
- gtk_widget_set_sensitive (temp_button, image_uri != NULL);
- g_free (image_uri);
+
+ gtk_widget_set_sensitive (temp_button, FALSE);
+ for (l = window->details->original_files; l != NULL; l = l->next) {
+ char *image_uri = nautilus_file_get_metadata
+ (NAUTILUS_FILE (l->data),
+ NAUTILUS_METADATA_KEY_CUSTOM_ICON, NULL);
+ if (image_uri) {
+ gtk_widget_set_sensitive (temp_button, TRUE);
+ }
+
+ g_free (image_uri);
+ }
+ }
+}
+
+static GHashTable *
+get_initial_emblems (GList *files)
+{
+ GHashTable *ret;
+ GList *l;
+
+ ret = g_hash_table_new_full (g_direct_hash,
+ g_direct_equal,
+ NULL,
+ (GDestroyNotify)eel_g_list_free_deep);
+
+ for (l = files; l != NULL; l = l->next) {
+ NautilusFile *file;
+ GList *keywords;
+
+ file = NAUTILUS_FILE (l->data);
+
+ keywords = nautilus_file_get_keywords (file);
+ g_hash_table_insert (ret, file, keywords);
}
+
+ return ret;
}
static void
@@ -1762,11 +2327,8 @@ create_emblems_page (FMPropertiesWindow *window)
char *emblem_name;
GdkPixbuf *pixbuf;
char *label;
- NautilusFile *file;
GList *icons, *l;
- file = window->details->original_file;
-
/* The emblems wrapped table */
scroller = eel_scrolled_wrap_table_new (TRUE, &emblems_table);
@@ -1779,6 +2341,8 @@ create_emblems_page (FMPropertiesWindow *window)
icons = nautilus_emblem_list_availible ();
+ window->details->initial_emblems = get_initial_emblems (window->details->original_files);
+
l = icons;
while (l != NULL) {
emblem_name = l->data;
@@ -1808,133 +2372,222 @@ create_emblems_page (FMPropertiesWindow *window)
g_object_unref (pixbuf);
/* Attach parameters and signal handler. */
- g_object_set_data_full (G_OBJECT (button), "nautilus_property_name",
+ g_object_set_data_full (G_OBJECT (button), "nautilus_emblem_name",
nautilus_emblem_get_keyword_from_icon_name (emblem_name), g_free);
- nautilus_file_ref (file);
- g_object_set_data_full (G_OBJECT (button), "nautilus_file",
- file, (GDestroyNotify) nautilus_file_unref);
-
- g_signal_connect (button, "toggled",
- G_CALLBACK (property_button_toggled), NULL);
+ window->details->emblem_buttons =
+ g_list_append (window->details->emblem_buttons,
+ button);
- /* Set initial state of button. */
- property_button_update (GTK_TOGGLE_BUTTON (button));
-
- /* Update button when file changes in future. */
- g_signal_connect_object (file, "changed",
- G_CALLBACK (property_button_update), button,
- G_CONNECT_SWAPPED);
+ g_signal_connect_object (button, "toggled",
+ G_CALLBACK (emblem_button_toggled),
+ G_OBJECT (window),
+ 0);
gtk_container_add (GTK_CONTAINER (emblems_table), button);
}
eel_g_list_free_deep (icons);
-
gtk_widget_show_all (emblems_table);
}
static void
-update_permissions_check_button_state (GtkWidget *check_button, NautilusFile *file)
+permission_change_callback (NautilusFile *file, GnomeVFSResult result, gpointer callback_data)
{
- GnomeVFSFilePermissions file_permissions, permission;
- gulong toggled_signal_id;
+ g_assert (callback_data == NULL);
+
+ /* Report the error if it's an error. */
+ fm_report_error_setting_permissions (file, result, NULL);
+}
- g_assert (GTK_IS_CHECK_BUTTON (check_button));
- g_assert (NAUTILUS_IS_FILE (file));
+static void
+get_initial_permission_state (FMPropertiesWindow *window,
+ GnomeVFSFilePermissions mask,
+ GList **on,
+ GList **off)
+{
+ GList *l;
+
+ *on = NULL;
+ *off = NULL;
+
+ for (l = window->details->target_files; l != NULL; l = l->next) {
+ GnomeVFSFilePermissions permissions;
+
+ permissions = GPOINTER_TO_INT (g_hash_table_lookup (window->details->initial_permissions,
+ l->data));
+
+ if ((permissions & mask) != 0) {
+ *on = g_list_prepend (*on, l->data);
+ } else {
+ *off = g_list_prepend (*off, l->data);
+ }
+ }
+}
- if (nautilus_file_is_gone (file)) {
- return;
+static void
+permission_button_toggled (GtkToggleButton *button,
+ FMPropertiesWindow *window)
+{
+ GList *l;
+ GnomeVFSFilePermissions permission_mask;
+ GList *files_on;
+ GList *files_off;
+
+ permission_mask = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (button),
+ "permission"));
+
+ files_on = NULL;
+ files_off = NULL;
+ if (gtk_toggle_button_get_active (button)
+ && !gtk_toggle_button_get_inconsistent (button)) {
+ /* Go to the initial state unless the initial state was
+ consistent */
+ get_initial_permission_state (window, permission_mask,
+ &files_on, &files_off);
+
+ if (!(files_on && files_off)) {
+ g_list_free (files_on);
+ g_list_free (files_off);
+ files_on = g_list_copy (window->details->target_files);
+ files_off = NULL;
+ }
+ } else if (gtk_toggle_button_get_inconsistent (button)
+ && !gtk_toggle_button_get_active (button)) {
+ files_on = g_list_copy (window->details->target_files);
+ files_off = NULL;
+ } else {
+ files_off = g_list_copy (window->details->target_files);
+ files_on = NULL;
}
- g_assert (nautilus_file_can_get_permissions (file));
+ g_signal_handlers_block_by_func (G_OBJECT (button),
+ G_CALLBACK (permission_button_toggled),
+ window);
+
+ gtk_toggle_button_set_active (button, files_on != NULL);
+ gtk_toggle_button_set_inconsistent (button, files_on && files_off);
- toggled_signal_id = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (check_button),
- "toggled_signal_id"));
- permission = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (check_button),
- "permission"));
- g_assert (toggled_signal_id != 0);
- g_assert (permission != 0);
+ g_signal_handlers_unblock_by_func (G_OBJECT (button),
+ G_CALLBACK (permission_button_toggled),
+ window);
- file_permissions = nautilus_file_get_permissions (file);
- gtk_widget_set_sensitive (GTK_WIDGET (check_button),
- nautilus_file_can_set_permissions (file));
+ for (l = files_on; l != NULL; l = l->next) {
+ NautilusFile *file;
+
+ file = NAUTILUS_FILE (l->data);
- /* Don't react to the "toggled" signal here to avoid recursion. */
- g_signal_handler_block (check_button, toggled_signal_id);
- gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check_button),
- (file_permissions & permission) != 0);
- g_signal_handler_unblock (check_button, toggled_signal_id);
-}
+ if (nautilus_file_can_set_permissions (file)) {
+ GnomeVFSFilePermissions permissions;
-static void
-permission_change_callback (NautilusFile *file, GnomeVFSResult result, gpointer callback_data)
-{
- g_assert (callback_data == NULL);
+ permissions = nautilus_file_get_permissions (file);
+ permissions |= permission_mask;
+ nautilus_file_set_permissions
+ (file, permissions,
+ permission_change_callback,
+ NULL);
+ }
+
+ }
- /* Report the error if it's an error. */
- fm_report_error_setting_permissions (file, result, NULL);
+ for (l = files_off; l != NULL; l = l->next) {
+ NautilusFile *file;
+
+ file = NAUTILUS_FILE (l->data);
+
+ if (nautilus_file_can_set_permissions (file)) {
+ GnomeVFSFilePermissions permissions;
+
+ permissions = nautilus_file_get_permissions (file);
+ permissions &= ~permission_mask;
+
+ nautilus_file_set_permissions
+ (file, permissions,
+ permission_change_callback,
+ NULL);
+ }
+ }
+
+ g_list_free (files_on);
+ g_list_free (files_off);
}
static void
-permissions_check_button_toggled (GtkToggleButton *toggle_button, gpointer user_data)
+permission_button_update (FMPropertiesWindow *window,
+ GtkToggleButton *button)
{
- NautilusFile *file;
- GnomeVFSFilePermissions permissions, permission_mask;
+ GList *l;
+ gboolean all_set;
+ gboolean all_unset;
+ gboolean all_cannot_set;
+ GnomeVFSFilePermissions button_permission;
+
+ button_permission = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (button),
+ "permission"));
+
+ all_set = TRUE;
+ all_unset = TRUE;
+ all_cannot_set = TRUE;
+ for (l = window->details->target_files; l != NULL; l = l->next) {
+ NautilusFile *file;
+ GnomeVFSFilePermissions file_permissions;
+
+ file = NAUTILUS_FILE (l->data);
- g_assert (NAUTILUS_IS_FILE (user_data));
+ if (!nautilus_file_can_get_permissions (file)) {
+ continue;
+ }
- file = NAUTILUS_FILE (user_data);
- g_assert (nautilus_file_can_get_permissions (file));
- g_assert (nautilus_file_can_set_permissions (file));
+ file_permissions = nautilus_file_get_permissions (file);
- permission_mask = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (toggle_button),
- "permission"));
+ if ((file_permissions & button_permission) != 0) {
+ all_unset = FALSE;
+ } else {
+ all_set = FALSE;
+ }
- /* Modify the file's permissions according to the state of this check button. */
- permissions = nautilus_file_get_permissions (file);
- if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (toggle_button))) {
- /* Turn this specific permission bit on. */
- permissions |= permission_mask;
- } else {
- /* Turn this specific permission bit off. */
- permissions &= ~permission_mask;
+ if (nautilus_file_can_set_permissions (file)) {
+ all_cannot_set = FALSE;
+ }
}
+
+ g_signal_handlers_block_by_func (G_OBJECT (button),
+ G_CALLBACK (permission_button_toggled),
+ window);
+
+ gtk_toggle_button_set_active (button, !all_unset);
+ gtk_toggle_button_set_inconsistent (button, !all_unset && !all_set);
+ gtk_widget_set_sensitive (GTK_WIDGET (button), !all_cannot_set);
- /* Try to change file permissions. If this fails, complain to user. */
- nautilus_file_set_permissions
- (file, permissions,
- permission_change_callback, NULL);
+ g_signal_handlers_unblock_by_func (G_OBJECT (button),
+ G_CALLBACK (permission_button_toggled),
+ window);
}
+
static void
-set_up_permissions_checkbox (GtkWidget *check_button,
- NautilusFile *file,
+set_up_permissions_checkbox (FMPropertiesWindow *window,
+ GtkWidget *check_button,
GnomeVFSFilePermissions permission)
{
- gulong toggled_signal_id;
-
- toggled_signal_id = g_signal_connect (check_button, "toggled",
- G_CALLBACK (permissions_check_button_toggled),
- file);
-
/* Load up the check_button with data we'll need when updating its state. */
- g_object_set_data (G_OBJECT (check_button), "toggled_signal_id",
- GUINT_TO_POINTER (toggled_signal_id));
g_object_set_data (G_OBJECT (check_button), "permission",
GINT_TO_POINTER (permission));
+ g_object_set_data (G_OBJECT (check_button), "properties_window",
+ window);
- /* Set initial state. */
- update_permissions_check_button_state (check_button, file);
+ window->details->permission_buttons =
+ g_list_prepend (window->details->permission_buttons,
+ check_button);
- /* Update state later if file changes. */
- g_signal_connect_object (file, "changed",
- G_CALLBACK (update_permissions_check_button_state),
- check_button, G_CONNECT_SWAPPED);
+ g_signal_connect_object (check_button, "toggled",
+ G_CALLBACK (permission_button_toggled),
+ window,
+ 0);
}
static void
-add_permissions_checkbox (GtkTable *table,
- NautilusFile *file,
+add_permissions_checkbox (FMPropertiesWindow *window,
+ GtkTable *table,
int row, int column,
GnomeVFSFilePermissions permission_to_check)
{
@@ -1957,7 +2610,9 @@ add_permissions_checkbox (GtkTable *table,
GTK_FILL, 0,
0, 0);
- set_up_permissions_checkbox (check_button, file, permission_to_check);
+ set_up_permissions_checkbox (window,
+ check_button,
+ permission_to_check);
}
static GtkWidget *
@@ -1980,7 +2635,9 @@ append_special_execution_checkbox (FMPropertiesWindow *window,
GTK_FILL, 0,
0, 0);
- set_up_permissions_checkbox (check_button, window->details->target_file, permission_to_check);
+ set_up_permissions_checkbox (window,
+ check_button,
+ permission_to_check);
++window->details->num_special_flags_rows;
return check_button;
@@ -2014,9 +2671,10 @@ update_visibility_of_special_flags_widgets_wrapper (gpointer callback_data)
}
static void
-append_special_execution_flags (FMPropertiesWindow *window,
- GtkTable *table)
+append_special_execution_flags (FMPropertiesWindow *window, GtkTable *table)
{
+
+
remember_special_flags_widget (window, append_special_execution_checkbox
(window, table, _("Set _user ID"), GNOME_VFS_PERM_SUID));
@@ -2042,24 +2700,84 @@ append_special_execution_flags (FMPropertiesWindow *window,
}
+static gboolean
+all_can_get_permissions (GList *file_list)
+{
+ GList *l;
+ for (l = file_list; l != NULL; l = l->next) {
+ NautilusFile *file;
+
+ file = NAUTILUS_FILE (l->data);
+
+ if (!nautilus_file_can_get_permissions (file)) {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+static gboolean
+all_can_set_permissions (GList *file_list)
+{
+ GList *l;
+ for (l = file_list; l != NULL; l = l->next) {
+ NautilusFile *file;
+
+ file = NAUTILUS_FILE (l->data);
+
+ if (!nautilus_file_can_set_permissions (file)) {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+static GHashTable *
+get_initial_permissions (GList *file_list)
+{
+ GHashTable *ret;
+ GList *l;
+
+ ret = g_hash_table_new (g_direct_hash,
+ g_direct_equal);
+
+ for (l = file_list; l != NULL; l = l->next) {
+ GnomeVFSFilePermissions permissions;
+ NautilusFile *file;
+
+ file = NAUTILUS_FILE (l->data);
+
+ permissions = nautilus_file_get_permissions (file);
+ g_hash_table_insert (ret, file,
+ GINT_TO_POINTER (permissions));
+ }
+
+ return ret;
+}
+
static void
create_permissions_page (FMPropertiesWindow *window)
{
GtkWidget *vbox;
GtkTable *page_table, *check_button_table;
char *file_name, *prompt_text;
- NautilusFile *file;
guint last_row;
guint checkbox_titles_row;
GtkLabel *group_label;
GtkOptionMenu *group_menu;
+ GList *file_list;
- file = window->details->target_file;
+ vbox = create_page_with_vbox (window->details->notebook,
+ _("Permissions"));
- vbox = create_page_with_vbox (window->details->notebook, _("Permissions"));
+ file_list = window->details->original_files;
- if (nautilus_file_can_get_permissions (file)) {
- if (!nautilus_file_can_set_permissions (file)) {
+ window->details->initial_permissions = get_initial_permissions (window->details->target_files);
+
+ if (all_can_get_permissions (file_list)) {
+ 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."));
@@ -2076,21 +2794,27 @@ create_permissions_page (FMPropertiesWindow *window)
TRUE, TRUE, 0);
attach_title_field (page_table, last_row, _("File owner:"));
- if (nautilus_file_can_set_owner (file)) {
+
+
+ if (!is_multi_file_window (window) && nautilus_file_can_set_owner (get_target_file (window))) {
/* Option menu in this case. */
- attach_owner_menu (page_table, last_row, file);
+ attach_owner_menu (page_table, last_row, get_target_file (window));
} else {
/* Static text in this case. */
- attach_value_field (page_table, last_row, VALUE_COLUMN, file, "owner");
+ attach_value_field (window,
+ page_table, last_row, VALUE_COLUMN,
+ "owner",
+ _("--"),
+ FALSE);
}
- if (nautilus_file_can_set_group (file)) {
+ 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);
/* Option menu in this case. */
group_menu = attach_group_menu (page_table, last_row,
- file);
+ get_target_file (window));
gtk_label_set_mnemonic_widget (GTK_LABEL (group_label),
GTK_WIDGET (group_menu));
} else {
@@ -2098,11 +2822,15 @@ create_permissions_page (FMPropertiesWindow *window)
_("File group:"),
NULL);
/* Static text in this case. */
- attach_value_field (page_table, last_row, VALUE_COLUMN, file, "group");
+ attach_value_field (window, page_table, last_row,
+ VALUE_COLUMN,
+ "group",
+ _("--"),
+ FALSE);
}
append_separator (page_table);
-
+
checkbox_titles_row = append_title_field (page_table, _("Owner:"), NULL);
append_title_field (page_table, _("Group:"), NULL);
append_title_field (page_table, _("Others:"), NULL);
@@ -2119,47 +2847,56 @@ create_permissions_page (FMPropertiesWindow *window)
0, 0,
0, 0);
- add_permissions_checkbox (check_button_table, file,
+ add_permissions_checkbox (window,
+ check_button_table,
PERMISSIONS_CHECKBOXES_OWNER_ROW,
PERMISSIONS_CHECKBOXES_READ_COLUMN,
GNOME_VFS_PERM_USER_READ);
- add_permissions_checkbox (check_button_table, file,
+ add_permissions_checkbox (window,
+ check_button_table,
PERMISSIONS_CHECKBOXES_OWNER_ROW,
PERMISSIONS_CHECKBOXES_WRITE_COLUMN,
GNOME_VFS_PERM_USER_WRITE);
- add_permissions_checkbox (check_button_table, file,
+ add_permissions_checkbox (window,
+ check_button_table,
PERMISSIONS_CHECKBOXES_OWNER_ROW,
PERMISSIONS_CHECKBOXES_EXECUTE_COLUMN,
GNOME_VFS_PERM_USER_EXEC);
- add_permissions_checkbox (check_button_table, file,
+ add_permissions_checkbox (window,
+ check_button_table,
PERMISSIONS_CHECKBOXES_GROUP_ROW,
PERMISSIONS_CHECKBOXES_READ_COLUMN,
GNOME_VFS_PERM_GROUP_READ);
- add_permissions_checkbox (check_button_table, file,
+ add_permissions_checkbox (window,
+ check_button_table,
PERMISSIONS_CHECKBOXES_GROUP_ROW,
PERMISSIONS_CHECKBOXES_WRITE_COLUMN,
GNOME_VFS_PERM_GROUP_WRITE);
- add_permissions_checkbox (check_button_table, file,
+ add_permissions_checkbox (window,
+ check_button_table,
PERMISSIONS_CHECKBOXES_GROUP_ROW,
PERMISSIONS_CHECKBOXES_EXECUTE_COLUMN,
GNOME_VFS_PERM_GROUP_EXEC);
- add_permissions_checkbox (check_button_table, file,
+ add_permissions_checkbox (window,
+ check_button_table,
PERMISSIONS_CHECKBOXES_OTHERS_ROW,
PERMISSIONS_CHECKBOXES_READ_COLUMN,
GNOME_VFS_PERM_OTHER_READ);
- add_permissions_checkbox (check_button_table, file,
+ add_permissions_checkbox (window,
+ check_button_table,
PERMISSIONS_CHECKBOXES_OTHERS_ROW,
PERMISSIONS_CHECKBOXES_WRITE_COLUMN,
GNOME_VFS_PERM_OTHER_WRITE);
- add_permissions_checkbox (check_button_table, file,
+ add_permissions_checkbox (window,
+ check_button_table,
PERMISSIONS_CHECKBOXES_OTHERS_ROW,
PERMISSIONS_CHECKBOXES_EXECUTE_COLUMN,
GNOME_VFS_PERM_OTHER_EXEC);
@@ -2167,15 +2904,28 @@ create_permissions_page (FMPropertiesWindow *window)
append_separator (page_table);
append_special_execution_flags (window, page_table);
-
- append_title_value_pair (page_table, _("Text view:"), file, "permissions");
- append_title_value_pair (page_table, _("Number view:"), file, "octal_permissions");
- append_title_value_pair (page_table, _("Last changed:"), file, "date_permissions");
+ append_title_value_pair
+ (window, page_table, _("Text view:"),
+ "permissions", _("--"),
+ FALSE);
+ 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 {
- file_name = nautilus_file_get_display_name (file);
- prompt_text = g_strdup_printf (_("The permissions of \"%s\" could not be determined."), file_name);
- g_free (file_name);
+ 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."));
+ }
+
add_prompt (GTK_VBOX (vbox), prompt_text, TRUE);
g_free (prompt_text);
}
@@ -2205,6 +2955,28 @@ bonobo_page_error_message (const char *view_name,
return hbox;
}
+static CORBA_sequence_CORBA_string *
+get_uri_list (GList *file_list)
+{
+ CORBA_sequence_CORBA_string *uri_list;
+ GList *l;
+ int i;
+
+ uri_list = CORBA_sequence_CORBA_string__alloc ();
+ uri_list->_maximum = g_list_length (file_list);
+ uri_list->_length = uri_list->_maximum;
+ uri_list->_buffer = CORBA_sequence_CORBA_string_allocbuf (uri_list->_length);
+ for (i = 0, l = file_list; l != NULL; i++, l = l->next) {
+ char *uri;
+
+ uri = nautilus_file_get_uri (NAUTILUS_FILE (l->data));
+ uri_list->_buffer[i] = CORBA_string_dup (uri);
+ g_free (uri);
+ }
+
+ return uri_list;
+}
+
static void
bonobo_page_activate_callback (CORBA_Object obj,
const char *error_reason,
@@ -2226,23 +2998,54 @@ bonobo_page_activate_callback (CORBA_Object obj,
if (obj != CORBA_OBJECT_NIL) {
Bonobo_Control control;
Bonobo_PropertyBag pb;
- BonoboArg *arg;
- char *uri;
-
- uri = nautilus_file_get_uri (window->details->target_file);
+ GList *keys;
control = Bonobo_Unknown_queryInterface
(obj, "IDL:Bonobo/Control:1.0", &ev);
-
pb = Bonobo_Control_getProperties (control, &ev);
if (!BONOBO_EX (&ev)) {
- arg = bonobo_arg_new (BONOBO_ARG_STRING);
- BONOBO_ARG_SET_STRING (arg, uri);
+ gboolean new_property;
+
+ keys = bonobo_pbclient_get_keys (pb, NULL);
+ new_property = FALSE;
+ if (g_list_find_custom (keys, "uris", (GCompareFunc)strcmp)) {
+ new_property = TRUE;
+ }
+ bonobo_pbclient_free_keys (keys);
+
+ if (new_property) {
+ /* Set the 'uris' property. */
+ CORBA_sequence_CORBA_string *uri_list;
+ BonoboArg *arg;
+
+ uri_list = get_uri_list (window->details->target_files);
+ arg = bonobo_arg_new (TC_CORBA_sequence_CORBA_string);
+ arg->_value = uri_list;
+ bonobo_pbclient_set_value_async (pb, "uris", arg, &ev);
+ bonobo_arg_release (arg);
+ } else {
+ /* Set the 'URI' property. */
+ BonoboArg *arg;
+ char *uri;
+
+ if (is_multi_file_window (window)) {
+ g_warning ("Multifile property page does not support the 'uris' property");
+ bonobo_object_release_unref (pb, NULL);
+ bonobo_object_release_unref (control, NULL);
+ return;
+ }
+
+ uri = nautilus_file_get_uri (get_target_file (window));
+
+ arg = bonobo_arg_new (BONOBO_ARG_STRING);
+ BONOBO_ARG_SET_STRING (arg, uri);
+ bonobo_pbclient_set_value_async (pb, "URI", arg, &ev);
+ bonobo_arg_release (arg);
+ g_free (uri);
+ }
- bonobo_pbclient_set_value_async (pb, "URI", arg, &ev);
- bonobo_arg_release (arg);
bonobo_object_release_unref (pb, NULL);
if (!BONOBO_EX (&ev)) {
@@ -2251,8 +3054,6 @@ bonobo_page_activate_callback (CORBA_Object obj,
bonobo_object_release_unref (control, &ev);
}
}
-
- g_free (uri);
}
if (widget == NULL) {
@@ -2267,16 +3068,42 @@ bonobo_page_activate_callback (CORBA_Object obj,
g_free (data);
}
+static gboolean
+can_handle_multiple_files (Bonobo_ServerInfo *info)
+{
+ Bonobo_ActivationProperty *prop;
+
+ prop = bonobo_server_info_prop_find (info, "nautilus:can_handle_multiple_files");
+
+ return prop && prop->v._u.value_boolean;
+}
+
static void
append_bonobo_pages (FMPropertiesWindow *window)
{
- GList *components, *l;
+ GList *all_components, *l;
+ GList *components;
CORBA_Environment ev;
/* find all the property pages for this file */
- components = nautilus_mime_get_property_components_for_file
- (window->details->target_file);
+ all_components = nautilus_mime_get_property_components_for_files
+ (window->details->target_files);
+ /* filter out property pages that don't support multiple files */
+ if (is_multi_file_window (window)) {
+ components = NULL;
+ for (l = all_components; l != NULL; l = l->next) {
+ if (can_handle_multiple_files (l->data)) {
+ components = g_list_prepend (components,
+ l->data);
+ }
+ }
+ components = g_list_reverse (components);
+ g_list_free (all_components);
+ } else {
+ components = all_components;
+ }
+
CORBA_exception_init (&ev);
l = components;
@@ -2317,7 +3144,8 @@ should_show_emblems (FMPropertiesWindow *window)
* we shouldn't pretend that they work by showing them here.
* When bug 5643 is fixed we can remove this case.
*/
- if (is_merged_trash_directory (window->details->target_file)) {
+ if (!is_multi_file_window (window)
+ && is_merged_trash_directory (get_target_file (window))) {
return FALSE;
}
@@ -2330,24 +3158,62 @@ should_show_permissions (FMPropertiesWindow *window)
/* Don't show permissions for the Trash since it's not
* really a file system object.
*/
- if (is_merged_trash_directory (window->details->target_file)) {
+ if (!is_multi_file_window (window)
+ && is_merged_trash_directory (get_target_file (window))) {
return FALSE;
}
return TRUE;
}
+static char *
+get_pending_key (GList *file_list)
+{
+ GList *l;
+ GList *uris;
+ GString *key;
+ char *ret;
+
+ uris = NULL;
+ for (l = file_list; l != NULL; l = l->next) {
+ uris = g_list_prepend (uris, nautilus_file_get_uri (NAUTILUS_FILE (l->data)));
+ }
+ uris = g_list_sort (uris, (GCompareFunc)strcmp);
+
+ key = g_string_new ("");
+ for (l = uris; l != NULL; l = l->next) {
+ g_string_append (key, l->data);
+ g_string_append (key, ";");
+ }
+
+ eel_g_list_free_deep (uris);
+
+ ret = key->str;
+ g_string_free (key, FALSE);
+
+ return ret;
+}
+
static StartupData *
-startup_data_new (NautilusFile *original_file,
- NautilusFile *target_file,
+startup_data_new (GList *original_files,
+ GList *target_files,
+ const char *pending_key,
FMDirectoryView *directory_view)
{
StartupData *data;
+ GList *l;
data = g_new0 (StartupData, 1);
- data->original_file = nautilus_file_ref (original_file);
- data->target_file = nautilus_file_ref (target_file);
+ data->original_files = nautilus_file_list_copy (original_files);
+ data->target_files = nautilus_file_list_copy (target_files);
data->directory_view = directory_view;
+ data->pending_key = g_strdup (pending_key);
+ data->pending_files = g_hash_table_new (g_direct_hash,
+ g_direct_equal);
+
+ for (l = data->target_files; l != NULL; l = l->next) {
+ g_hash_table_insert (data->pending_files, l->data, l->data);
+ }
return data;
}
@@ -2355,8 +3221,10 @@ startup_data_new (NautilusFile *original_file,
static void
startup_data_free (StartupData *data)
{
- nautilus_file_unref (data->original_file);
- nautilus_file_unref (data->target_file);
+ nautilus_file_list_free (data->original_files);
+ nautilus_file_list_free (data->target_files);
+ g_hash_table_destroy (data->pending_files);
+ g_free (data->pending_key);
g_free (data);
}
@@ -2384,45 +3252,74 @@ static FMPropertiesWindow *
create_properties_window (StartupData *startup_data)
{
FMPropertiesWindow *window;
- NautilusFileAttributes attributes;
GtkWidget *vbox;
GtkWidget *hbox;
GtkWidget *button;
+ GList *l;
window = FM_PROPERTIES_WINDOW (gtk_widget_new (fm_properties_window_get_type (), NULL));
- window->details->original_file = nautilus_file_ref (startup_data->original_file);
- window->details->target_file = nautilus_file_ref (startup_data->target_file);
+ window->details->original_files = nautilus_file_list_copy (startup_data->original_files);
+ window->details->target_files = nautilus_file_list_copy (startup_data->target_files);
+
gtk_window_set_wmclass (GTK_WINDOW (window), "file_properties", "Nautilus");
gtk_window_set_resizable (GTK_WINDOW (window), FALSE);
gtk_window_set_screen (GTK_WINDOW (window),
gtk_widget_get_screen (GTK_WIDGET (startup_data->directory_view)));
/* Set initial window title */
- update_properties_window_title (GTK_WINDOW (window), window->details->target_file);
+ update_properties_window_title (window);
/* Start monitoring the file attributes we display. Note that some
* of the attributes are for the original file, and some for the
- * target file.
+ * target files.
*/
- attributes = nautilus_icon_factory_get_required_file_attributes ();
- attributes |= NAUTILUS_FILE_ATTRIBUTE_DISPLAY_NAME;
- nautilus_file_monitor_add (window->details->original_file, window, attributes);
- attributes = 0;
- if (nautilus_file_is_directory (window->details->target_file)) {
- attributes |= NAUTILUS_FILE_ATTRIBUTE_DEEP_COUNTS;
+ for (l = window->details->original_files; l != NULL; l = l->next) {
+ NautilusFile *file;
+ NautilusFileAttributes attributes;
+
+ file = NAUTILUS_FILE (l->data);
+
+ attributes = nautilus_icon_factory_get_required_file_attributes ();
+ attributes |= NAUTILUS_FILE_ATTRIBUTE_DISPLAY_NAME;
+
+ nautilus_file_monitor_add (NAUTILUS_FILE (l->data),
+ window,
+ attributes);
}
- attributes |= NAUTILUS_FILE_ATTRIBUTE_METADATA;
- nautilus_file_monitor_add (window->details->target_file, window, attributes);
+ for (l = window->details->target_files; l != NULL; l = l->next) {
+ NautilusFile *file;
+ NautilusFileAttributes attributes;
+
+ file = NAUTILUS_FILE (l->data);
+
+ attributes = 0;
+ if (nautilus_file_is_directory (file)) {
+ attributes |= NAUTILUS_FILE_ATTRIBUTE_DEEP_COUNTS;
+ }
+
+ attributes |= NAUTILUS_FILE_ATTRIBUTE_METADATA;
+ nautilus_file_monitor_add (file, window, attributes);
+ }
+
+ for (l = window->details->target_files; l != NULL; l = l->next) {
+ g_signal_connect_object (NAUTILUS_FILE (l->data),
+ "changed",
+ G_CALLBACK (properties_window_update),
+ G_OBJECT (window),
+ G_CONNECT_SWAPPED);
+ }
- /* React to future property changes and file deletions. */
- window->details->file_changed_handler_id =
- g_signal_connect_object (window->details->target_file, "changed",
- G_CALLBACK (properties_window_file_changed_callback),
- window, G_CONNECT_SWAPPED);
+ for (l = window->details->original_files; l != NULL; l = l->next) {
+ g_signal_connect_object (NAUTILUS_FILE (l->data),
+ "changed",
+ G_CALLBACK (properties_window_update),
+ G_OBJECT (window),
+ G_CONNECT_SWAPPED);
+ }
/* Create box for notebook and button box. */
vbox = gtk_vbox_new (FALSE, 0);
@@ -2473,67 +3370,70 @@ create_properties_window (StartupData *startup_data)
G_CALLBACK (gtk_widget_destroy),
window);
+ /* Update from initial state */
+ properties_window_update (window, NULL);
+
return window;
}
-static NautilusFile *
-get_target_file (NautilusFile *file)
+static GList *
+get_target_file_list (GList *original_files)
{
- NautilusFile *target_file;
- char *uri_to_display;
- NautilusDesktopLink *link;
-
- target_file = NULL;
- if (NAUTILUS_IS_DESKTOP_ICON_FILE (file)) {
- link = nautilus_desktop_icon_file_get_link (NAUTILUS_DESKTOP_ICON_FILE (file));
+ GList *ret;
+ GList *l;
+
+ ret = NULL;
+
+ for (l = original_files; l != NULL; l = l->next) {
+ NautilusFile *target;
- /* map to linked URI for these types of links */
- uri_to_display = nautilus_desktop_link_get_activation_uri (link);
- if (uri_to_display) {
- target_file = nautilus_file_get (uri_to_display);
- g_free (uri_to_display);
- }
+ target = get_target_file_for_original_file (NAUTILUS_FILE (l->data));
- g_object_unref (link);
+ ret = g_list_prepend (ret, target);
}
- if (target_file != NULL) {
- return target_file;
- }
+ ret = g_list_reverse (ret);
- /* Ref passed-in file here since we've decided to use it. */
- nautilus_file_ref (file);
- return file;
+ return ret;
}
static void
-create_properties_window_callback (NautilusFile *file, gpointer callback_data)
+add_window (FMPropertiesWindow *window)
{
- FMPropertiesWindow *new_window;
- StartupData *startup_data;
-
- startup_data = (StartupData *)callback_data;
+ if (!is_multi_file_window (window)) {
+ g_hash_table_insert (windows,
+ get_original_file (window),
+ window);
+ g_object_set_data (G_OBJECT (window), "window_key",
+ get_original_file (window));
+ }
+}
- new_window = create_properties_window (startup_data);
+static void
+remove_window (FMPropertiesWindow *window)
+{
+ gpointer key;
- g_hash_table_insert (windows, startup_data->original_file, new_window);
+ key = g_object_get_data (G_OBJECT (window), "window_key");
+ if (key) {
+ g_hash_table_remove (windows, key);
+ }
+}
- remove_pending_file (startup_data, FALSE, TRUE, TRUE);
+static GtkWindow *
+get_existing_window (GList *file_list)
+{
+ if (!file_list->next) {
+ return g_hash_table_lookup (windows, file_list->data);
+ }
-/* FIXME bugzilla.gnome.org 42151:
- * See comment elsewhere in this file about bug 2151.
- */
-#ifdef UNDO_ENABLED
- nautilus_undo_share_undo_manager (GTK_OBJECT (new_window),
- GTK_OBJECT (callback_data));
-#endif
- gtk_window_present (GTK_WINDOW (new_window));
+ return NULL;
}
static void
cancel_create_properties_window_callback (gpointer callback_data)
{
- remove_pending_file ((StartupData *)callback_data, TRUE, FALSE, TRUE);
+ remove_pending ((StartupData *)callback_data, TRUE, FALSE, TRUE);
}
static void
@@ -2541,18 +3441,31 @@ directory_view_destroyed_callback (FMDirectoryView *view, gpointer callback_data
{
g_assert (view == ((StartupData *)callback_data)->directory_view);
- remove_pending_file ((StartupData *)callback_data, TRUE, TRUE, FALSE);
+ remove_pending ((StartupData *)callback_data, TRUE, TRUE, FALSE);
+}
+
+static void
+cancel_call_when_ready_callback (gpointer key,
+ gpointer value,
+ gpointer user_data)
+{
+ nautilus_file_cancel_call_when_ready
+ (NAUTILUS_FILE (key),
+ is_directory_ready_callback,
+ user_data);
}
static void
-remove_pending_file (StartupData *startup_data,
- gboolean cancel_call_when_ready,
- gboolean cancel_timed_wait,
- gboolean cancel_destroy_handler)
+remove_pending (StartupData *startup_data,
+ gboolean cancel_call_when_ready,
+ gboolean cancel_timed_wait,
+ gboolean cancel_destroy_handler)
{
if (cancel_call_when_ready) {
- nautilus_file_cancel_call_when_ready
- (startup_data->target_file, create_properties_window_callback, startup_data);
+ g_hash_table_foreach (startup_data->pending_files,
+ cancel_call_when_ready_callback,
+ startup_data);
+
}
if (cancel_timed_wait) {
eel_timed_wait_stop
@@ -2563,19 +3476,55 @@ remove_pending_file (StartupData *startup_data,
G_CALLBACK (directory_view_destroyed_callback),
startup_data);
}
- g_hash_table_remove (pending_files, startup_data->original_file);
+
+ g_hash_table_remove (pending_lists, startup_data->pending_key);
+
startup_data_free (startup_data);
}
+static void
+is_directory_ready_callback (NautilusFile *file,
+ gpointer data)
+{
+ StartupData *startup_data;
+
+ startup_data = data;
+
+ g_hash_table_remove (startup_data->pending_files, file);
+
+ if (g_hash_table_size (startup_data->pending_files) == 0) {
+ FMPropertiesWindow *new_window;
+
+ new_window = create_properties_window (startup_data);
+
+ add_window (new_window);
+
+ remove_pending (startup_data, FALSE, TRUE, TRUE);
+
+/* FIXME bugzilla.gnome.org 42151:
+ * See comment elsewhere in this file about bug 2151.
+ */
+#ifdef UNDO_ENABLED
+ nautilus_undo_share_undo_manager (GTK_OBJECT (new_window),
+ GTK_OBJECT (callback_data));
+#endif
+ gtk_window_present (GTK_WINDOW (new_window));
+ }
+}
+
+
void
-fm_properties_window_present (NautilusFile *original_file, FMDirectoryView *directory_view)
+fm_properties_window_present (GList *original_files,
+ FMDirectoryView *directory_view)
{
- GtkWindow *existing_window;
+ GList *l;
GtkWidget *parent_window;
- NautilusFile *target_file;
StartupData *startup_data;
+ GList *target_files;
+ GtkWindow *existing_window;
+ char *pending_key;
- g_return_if_fail (NAUTILUS_IS_FILE (original_file));
+ g_return_if_fail (original_files != NULL);
g_return_if_fail (FM_IS_DIRECTORY_VIEW (directory_view));
/* Create the hash tables first time through. */
@@ -2584,13 +3533,13 @@ fm_properties_window_present (NautilusFile *original_file, FMDirectoryView *dire
(NULL, NULL, "property windows");
}
- if (pending_files == NULL) {
- pending_files = eel_g_hash_table_new_free_at_exit
- (NULL, NULL, "pending property window files");
+ if (pending_lists == NULL) {
+ pending_lists = eel_g_hash_table_new_free_at_exit
+ (g_str_hash, g_str_equal, "pending property window files");
}
/* Look to see if there's already a window for this file. */
- existing_window = g_hash_table_lookup (windows, original_file);
+ existing_window = get_existing_window (original_files);
if (existing_window != NULL) {
gtk_window_set_screen (existing_window,
gtk_widget_get_screen (GTK_WIDGET (directory_view)));
@@ -2598,57 +3547,71 @@ fm_properties_window_present (NautilusFile *original_file, FMDirectoryView *dire
return;
}
+
+ pending_key = get_pending_key (original_files);
+
/* Look to see if we're already waiting for a window for this file. */
- if (g_hash_table_lookup (pending_files, original_file) != NULL) {
+ if (g_hash_table_lookup (pending_lists, pending_key) != NULL) {
return;
}
- target_file = get_target_file (original_file);
- startup_data = startup_data_new (original_file, target_file, directory_view);
- nautilus_file_unref (target_file);
+ target_files = get_target_file_list (original_files);
+
+ startup_data = startup_data_new (original_files,
+ target_files,
+ pending_key,
+ directory_view);
+
+ nautilus_file_list_free (target_files);
/* Wait until we can tell whether it's a directory before showing, since
* some one-time layout decisions depend on that info.
*/
- g_hash_table_insert (pending_files, target_file, target_file);
+ g_hash_table_insert (pending_lists, pending_key, pending_key);
g_signal_connect (directory_view, "destroy",
G_CALLBACK (directory_view_destroyed_callback), startup_data);
parent_window = gtk_widget_get_ancestor (GTK_WIDGET (directory_view), GTK_TYPE_WINDOW);
+
eel_timed_wait_start
(cancel_create_properties_window_callback,
startup_data,
_("Cancel Showing Properties Window?"),
_("Creating Properties window"),
parent_window == NULL ? NULL : GTK_WINDOW (parent_window));
- nautilus_file_call_when_ready
- (target_file, NAUTILUS_FILE_ATTRIBUTE_IS_DIRECTORY,
- create_properties_window_callback, startup_data);
+
+
+ for (l = startup_data->target_files; l != NULL; l = l->next) {
+ nautilus_file_call_when_ready
+ (NAUTILUS_FILE (l->data),
+ NAUTILUS_FILE_ATTRIBUTE_IS_DIRECTORY,
+ is_directory_ready_callback,
+ startup_data);
+ }
}
static void
real_destroy (GtkObject *object)
{
FMPropertiesWindow *window;
+ GList *l;
window = FM_PROPERTIES_WINDOW (object);
- g_hash_table_remove (windows, window->details->original_file);
-
- if (window->details->original_file != NULL) {
- nautilus_file_monitor_remove (window->details->original_file, window);
- nautilus_file_unref (window->details->original_file);
- window->details->original_file = NULL;
- }
+ remove_window (window);
- if (window->details->target_file != NULL) {
- g_signal_handler_disconnect (window->details->target_file,
- window->details->file_changed_handler_id);
- nautilus_file_monitor_remove (window->details->target_file, window);
- nautilus_file_unref (window->details->target_file);
- window->details->target_file = NULL;
+ for (l = window->details->original_files; l != NULL; l = l->next) {
+ nautilus_file_monitor_remove (NAUTILUS_FILE (l->data), window);
+ }
+ nautilus_file_list_free (window->details->original_files);
+ window->details->original_files = NULL;
+
+ for (l = window->details->target_files; l != NULL; l = l->next) {
+ nautilus_file_monitor_remove (NAUTILUS_FILE (l->data), window);
}
+ nautilus_file_list_free (window->details->target_files);
+ window->details->target_files = NULL;
window->details->name_field = NULL;
@@ -2658,11 +3621,29 @@ real_destroy (GtkObject *object)
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;
+
+ if (window->details->initial_emblems) {
+ 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);
+ window->details->initial_permissions = NULL;
+ }
+
+ g_list_free (window->details->value_fields);
+ window->details->value_fields = NULL;
+
if (window->details->update_directory_contents_timeout_id != 0) {
g_source_remove (window->details->update_directory_contents_timeout_id);
window->details->update_directory_contents_timeout_id = 0;
}
-
GTK_OBJECT_CLASS (parent_class)->destroy (object);
}
@@ -2673,6 +3654,8 @@ real_finalize (GObject *object)
window = FM_PROPERTIES_WINDOW (object);
+ eel_g_list_free_deep (window->details->mime_list);
+
g_free (window->details->pending_name);
g_free (window->details);
@@ -2690,19 +3673,23 @@ set_icon_callback (const char* icon_path, FMPropertiesWindow *properties_window)
g_return_if_fail (FM_IS_PROPERTIES_WINDOW (properties_window));
if (icon_path != NULL) {
- file = properties_window->details->original_file;
+ GList *l;
+
icon_uri = gnome_vfs_get_uri_from_local_path (icon_path);
- nautilus_file_set_metadata (file, NAUTILUS_METADATA_KEY_CUSTOM_ICON, NULL, icon_uri);
- g_free (icon_uri);
- nautilus_file_set_metadata (file, NAUTILUS_METADATA_KEY_ICON_SCALE, NULL, NULL);
+ for (l = properties_window->details->original_files; l != NULL; l = l->next) {
+ file = NAUTILUS_FILE (l->data);
+
+ nautilus_file_set_metadata (file, NAUTILUS_METADATA_KEY_CUSTOM_ICON, NULL, icon_uri);
+ nautilus_file_set_metadata (file, NAUTILUS_METADATA_KEY_ICON_SCALE, NULL, NULL);
+ }
+ g_free (icon_uri);
+
/* re-enable the property window's clear image button */
gtk_widget_set_sensitive (properties_window->details->remove_image_button, TRUE);
- } else {
}
}
-
/* handle the "select icon" button */
static void
select_image_button_callback (GtkWidget *widget, FMPropertiesWindow *properties_window)
@@ -2715,22 +3702,15 @@ select_image_button_callback (GtkWidget *widget, FMPropertiesWindow *properties_
NULL,
GTK_WINDOW (properties_window),
(EelIconSelectionFunction) set_icon_callback,
- properties_window);
+ properties_window);
}
static void
remove_image_button_callback (GtkWidget *widget, FMPropertiesWindow *properties_window)
{
- g_assert (FM_IS_PROPERTIES_WINDOW (properties_window));
+ g_return_if_fail (FM_IS_PROPERTIES_WINDOW (properties_window));
- nautilus_file_set_metadata (properties_window->details->original_file,
- NAUTILUS_METADATA_KEY_ICON_SCALE,
- NULL, NULL);
- nautilus_file_set_metadata (properties_window->details->original_file,
- NAUTILUS_METADATA_KEY_CUSTOM_ICON,
- NULL, NULL);
-
- gtk_widget_set_sensitive (widget, FALSE);
+ reset_icon (properties_window);
}
static void