summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/Makefile.am2
-rw-r--r--src/nautilus-file-conflict-dialog.c473
-rw-r--r--src/nautilus-file-conflict-dialog.h30
-rw-r--r--src/nautilus-file-operations.c147
-rw-r--r--src/nautilus-operations-ui-manager.c449
-rw-r--r--src/nautilus-operations-ui-manager.h27
6 files changed, 648 insertions, 480 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 652cab7ce..6532c0101 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -278,6 +278,8 @@ nautilus_no_main_sources = \
nautilus-rename-file-popover-controller.h \
nautilus-new-folder-dialog-controller.c \
nautilus-new-folder-dialog-controller.h \
+ nautilus-operations-ui-manager.c \
+ nautilus-operations-ui-manager.h \
nautilus-file-operations.c \
nautilus-file-operations.h \
nautilus-file-private.h \
diff --git a/src/nautilus-file-conflict-dialog.c b/src/nautilus-file-conflict-dialog.c
index bfce4c948..0ba63a117 100644
--- a/src/nautilus-file-conflict-dialog.c
+++ b/src/nautilus-file-conflict-dialog.c
@@ -32,18 +32,11 @@
#include "nautilus-file.h"
#include "nautilus-icon-info.h"
+#include "nautilus-operations-ui-manager.h"
struct _NautilusFileConflictDialogDetails
{
- /* conflicting objects */
- NautilusFile *source;
- NautilusFile *destination;
- NautilusFile *dest_dir;
-
gchar *conflict_name;
- NautilusFileListHandle *handle;
- gulong src_handler_id;
- gulong dest_handler_id;
/* UI objects */
GtkWidget *titles_vbox;
@@ -52,6 +45,7 @@ struct _NautilusFileConflictDialogDetails
GtkWidget *expander;
GtkWidget *entry;
GtkWidget *checkbox;
+ GtkWidget *skip_button;
GtkWidget *rename_button;
GtkWidget *replace_button;
GtkWidget *dest_image;
@@ -66,307 +60,128 @@ G_DEFINE_TYPE (NautilusFileConflictDialog,
(G_TYPE_INSTANCE_GET_PRIVATE ((object), NAUTILUS_TYPE_FILE_CONFLICT_DIALOG, \
NautilusFileConflictDialogDetails))
-static void
-file_icons_changed (NautilusFile *file,
- NautilusFileConflictDialog *fcd)
-{
- GdkPixbuf *pixbuf;
-
- pixbuf = nautilus_file_get_icon_pixbuf (fcd->details->destination,
- NAUTILUS_CANVAS_ICON_SIZE_SMALL,
- TRUE,
- gtk_widget_get_scale_factor (fcd->details->dest_image),
- NAUTILUS_FILE_ICON_FLAGS_USE_THUMBNAILS);
- gtk_image_set_from_pixbuf (GTK_IMAGE (fcd->details->dest_image), pixbuf);
- g_object_unref (pixbuf);
-
- pixbuf = nautilus_file_get_icon_pixbuf (fcd->details->source,
- NAUTILUS_CANVAS_ICON_SIZE_SMALL,
- TRUE,
- gtk_widget_get_scale_factor (fcd->details->src_image),
- NAUTILUS_FILE_ICON_FLAGS_USE_THUMBNAILS);
-
- gtk_image_set_from_pixbuf (GTK_IMAGE (fcd->details->src_image), pixbuf);
- g_object_unref (pixbuf);
+void
+nautilus_file_conflict_dialog_set_text (NautilusFileConflictDialog *fcd,
+ gchar *primary_text,
+ gchar *secondary_text)
+{
+ NautilusFileConflictDialogDetails *details = fcd->details;
+ GtkWidget *label;
+ PangoAttrList *attr_list;
+
+ label = gtk_label_new (primary_text);
+ gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
+ gtk_label_set_line_wrap_mode (GTK_LABEL (label), PANGO_WRAP_WORD_CHAR);
+ gtk_label_set_xalign (GTK_LABEL (label), 0.0);
+ gtk_box_pack_start (GTK_BOX (details->titles_vbox),
+ label, FALSE, FALSE, 0);
+ gtk_widget_show (label);
+
+ attr_list = pango_attr_list_new ();
+ pango_attr_list_insert (attr_list, pango_attr_weight_new (PANGO_WEIGHT_BOLD));
+ pango_attr_list_insert (attr_list, pango_attr_scale_new (PANGO_SCALE_LARGE));
+ g_object_set (label,
+ "attributes", attr_list,
+ NULL);
+
+ pango_attr_list_unref (attr_list);
+
+ label = gtk_label_new (secondary_text);
+ gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
+ gtk_label_set_xalign (GTK_LABEL (label), 0.0);
+ gtk_box_pack_start (GTK_BOX (details->titles_vbox),
+ label, FALSE, FALSE, 0);
+ gtk_widget_show (label);
}
-static void
-file_list_ready_cb (GList *files,
- gpointer user_data)
+void
+nautilus_file_conflict_dialog_set_images (NautilusFileConflictDialog *fcd,
+ GdkPixbuf *destination_pixbuf,
+ GdkPixbuf *source_pixbuf)
{
- NautilusFileConflictDialog *fcd = user_data;
- NautilusFile *src, *dest, *dest_dir;
- time_t src_mtime, dest_mtime;
- gboolean source_is_dir, dest_is_dir, should_show_type;
- NautilusFileConflictDialogDetails *details;
- char *primary_text, *message, *secondary_text;
- const gchar *message_extra;
- char *dest_name, *dest_dir_name, *edit_name;
- char *label_text;
- char *size, *date, *type = NULL;
- GdkPixbuf *pixbuf;
- GtkWidget *label;
- GString *str;
- PangoAttrList *attr_list;
-
- details = fcd->details;
-
- details->handle = NULL;
-
- dest_dir = g_list_nth_data (files, 0);
- dest = g_list_nth_data (files, 1);
- src = g_list_nth_data (files, 2);
-
- src_mtime = nautilus_file_get_mtime (src);
- dest_mtime = nautilus_file_get_mtime (dest);
-
- dest_name = nautilus_file_get_display_name (dest);
- dest_dir_name = nautilus_file_get_display_name (dest_dir);
-
- source_is_dir = nautilus_file_is_directory (src);
- dest_is_dir = nautilus_file_is_directory (dest);
-
- type = nautilus_file_get_mime_type (dest);
- should_show_type = !nautilus_file_is_mime_type (src, type);
-
- g_free (type);
- type = NULL;
-
- /* Set up the right labels */
- if (dest_is_dir) {
- if (source_is_dir) {
- primary_text = g_strdup_printf
- (_("Merge folder “%s”?"),
- dest_name);
-
- message_extra =
- _("Merging will ask for confirmation before replacing any files in "
- "the folder that conflict with the files being copied.");
-
- if (src_mtime > dest_mtime) {
- message = g_strdup_printf (
- _("An older folder with the same name already exists in “%s”."),
- dest_dir_name);
- } else if (src_mtime < dest_mtime) {
- message = g_strdup_printf (
- _("A newer folder with the same name already exists in “%s”."),
- dest_dir_name);
- } else {
- message = g_strdup_printf (
- _("Another folder with the same name already exists in “%s”."),
- dest_dir_name);
- }
- } else {
- message_extra =
- _("Replacing it will remove all files in the folder.");
- primary_text = g_strdup_printf
- (_("Replace folder “%s”?"), dest_name);
- message = g_strdup_printf
- (_("A folder with the same name already exists in “%s”."),
- dest_dir_name);
- }
- } else {
- primary_text = g_strdup_printf
- (_("Replace file “%s”?"), dest_name);
-
- message_extra = _("Replacing it will overwrite its content.");
-
- if (src_mtime > dest_mtime) {
- message = g_strdup_printf (
- _("An older file with the same name already exists in “%s”."),
- dest_dir_name);
- } else if (src_mtime < dest_mtime) {
- message = g_strdup_printf (
- _("A newer file with the same name already exists in “%s”."),
- dest_dir_name);
- } else {
- message = g_strdup_printf (
- _("Another file with the same name already exists in “%s”."),
- dest_dir_name);
- }
- }
-
- secondary_text = g_strdup_printf ("%s\n%s", message, message_extra);
- g_free (message);
-
- label = gtk_label_new (primary_text);
- gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
- gtk_label_set_line_wrap_mode (GTK_LABEL (label), PANGO_WRAP_WORD_CHAR);
- gtk_label_set_xalign (GTK_LABEL (label), 0.0);
- gtk_box_pack_start (GTK_BOX (details->titles_vbox),
- label, FALSE, FALSE, 0);
- gtk_widget_show (label);
-
- attr_list = pango_attr_list_new ();
- pango_attr_list_insert (attr_list, pango_attr_weight_new (PANGO_WEIGHT_BOLD));
- pango_attr_list_insert (attr_list, pango_attr_scale_new (PANGO_SCALE_LARGE));
- g_object_set (label,
- "attributes", attr_list,
- NULL);
-
- pango_attr_list_unref (attr_list);
-
- label = gtk_label_new (secondary_text);
- gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
- gtk_label_set_xalign (GTK_LABEL (label), 0.0);
- gtk_box_pack_start (GTK_BOX (details->titles_vbox),
- label, FALSE, FALSE, 0);
- gtk_widget_show (label);
- g_free (primary_text);
- g_free (secondary_text);
-
- /* Set up file icons */
- pixbuf = nautilus_file_get_icon_pixbuf (dest,
- NAUTILUS_CANVAS_ICON_SIZE_SMALL,
- TRUE,
- gtk_widget_get_scale_factor (fcd->details->titles_vbox),
- NAUTILUS_FILE_ICON_FLAGS_USE_THUMBNAILS);
- details->dest_image = gtk_image_new_from_pixbuf (pixbuf);
- gtk_box_pack_start (GTK_BOX (details->first_hbox),
- details->dest_image, FALSE, FALSE, 0);
- gtk_widget_show (details->dest_image);
- g_object_unref (pixbuf);
-
- pixbuf = nautilus_file_get_icon_pixbuf (src,
- NAUTILUS_CANVAS_ICON_SIZE_SMALL,
- TRUE,
- gtk_widget_get_scale_factor (fcd->details->titles_vbox),
- NAUTILUS_FILE_ICON_FLAGS_USE_THUMBNAILS);
- details->src_image = gtk_image_new_from_pixbuf (pixbuf);
- gtk_box_pack_start (GTK_BOX (details->second_hbox),
- details->src_image, FALSE, FALSE, 0);
- gtk_widget_show (details->src_image);
- g_object_unref (pixbuf);
-
- /* Set up labels */
- label = gtk_label_new (NULL);
- date = nautilus_file_get_string_attribute (dest,
- "date_modified");
- size = nautilus_file_get_string_attribute (dest, "size");
-
- if (should_show_type) {
- type = nautilus_file_get_string_attribute (dest, "type");
- }
-
- str = g_string_new (NULL);
- if (dest_is_dir) {
- g_string_append_printf (str, "<b>%s</b>\n", _("Original folder"));
- g_string_append_printf (str, "%s %s\n", _("Items:"), size);
- }
- else {
- g_string_append_printf (str, "<b>%s</b>\n", _("Original file"));
- g_string_append_printf (str, "%s %s\n", _("Size:"), size);
- }
-
- if (should_show_type) {
- g_string_append_printf (str, "%s %s\n", _("Type:"), type);
- }
-
- g_string_append_printf (str, "%s %s", _("Last modified:"), date);
-
- label_text = str->str;
- gtk_label_set_markup (GTK_LABEL (label),
- label_text);
- gtk_box_pack_start (GTK_BOX (details->first_hbox),
- label, FALSE, FALSE, 0);
- gtk_widget_show (label);
-
- g_free (size);
- g_free (type);
- g_free (date);
- g_string_erase (str, 0, -1);
-
- /* Second label */
- label = gtk_label_new (NULL);
- date = nautilus_file_get_string_attribute (src,
- "date_modified");
- size = nautilus_file_get_string_attribute (src, "size");
-
- if (should_show_type) {
- type = nautilus_file_get_string_attribute (src, "type");
- }
-
- if (source_is_dir) {
- g_string_append_printf (str, "<b>%s</b>\n", dest_is_dir ? _("Merge with") : _("Replace with"));
- g_string_append_printf (str, "%s %s\n", _("Items:"), size);
- }
- else {
- g_string_append_printf (str, "<b>%s</b>\n", _("Replace with"));
- g_string_append_printf (str, "%s %s\n", _("Size:"), size);
- }
-
- if (should_show_type) {
- g_string_append_printf (str, "%s %s\n", _("Type:"), type);
- }
-
- g_string_append_printf (str, "%s %s", _("Last modified:"), date);
- label_text = g_string_free (str, FALSE);
-
- gtk_label_set_markup (GTK_LABEL (label),
- label_text);
- gtk_box_pack_start (GTK_BOX (details->second_hbox),
- label, FALSE, FALSE, 0);
- gtk_widget_show (label);
+ NautilusFileConflictDialogDetails *details = fcd->details;
+
+ if (details->dest_image == NULL) {
+ details->dest_image = gtk_image_new_from_pixbuf (destination_pixbuf);
+ gtk_box_pack_start (GTK_BOX (details->first_hbox),
+ details->dest_image, FALSE, FALSE, 0);
+ gtk_widget_show (details->dest_image);
+ } else {
+ gtk_image_set_from_pixbuf (GTK_IMAGE (details->dest_image),
+ destination_pixbuf);
+ }
+
+ if (details->src_image == NULL) {
+ details->src_image = gtk_image_new_from_pixbuf (source_pixbuf);
+ gtk_box_pack_start (GTK_BOX (details->second_hbox),
+ details->src_image, FALSE, FALSE, 0);
+ gtk_widget_show (details->src_image);
+ } else {
+ gtk_image_set_from_pixbuf (GTK_IMAGE (details->src_image),
+ source_pixbuf);
+ }
+}
- g_free (size);
- g_free (date);
- g_free (type);
- g_free (label_text);
+void
+nautilus_file_conflict_dialog_set_file_labels (NautilusFileConflictDialog *fcd,
+ gchar *destination_label,
+ gchar *source_label)
+{
+ NautilusFileConflictDialogDetails *details = fcd->details;
+ GtkWidget *label;
+
+ label = gtk_label_new (NULL);
+ gtk_label_set_markup (GTK_LABEL (label),
+ destination_label);
+ gtk_box_pack_start (GTK_BOX (details->first_hbox),
+ label, FALSE, FALSE, 0);
+ gtk_widget_show (label);
+
+ label = gtk_label_new (NULL);
+ gtk_label_set_markup (GTK_LABEL (label),
+ source_label);
+ gtk_box_pack_start (GTK_BOX (details->second_hbox),
+ label, FALSE, FALSE, 0);
+ gtk_widget_show (label);
+}
- /* Populate the entry */
- edit_name = nautilus_file_get_edit_name (dest);
- details->conflict_name = edit_name;
+void
+nautilus_file_conflict_dialog_set_conflict_name (NautilusFileConflictDialog *fcd,
+ gchar *conflict_name)
+{
+ NautilusFileConflictDialogDetails *details = fcd->details;
- gtk_entry_set_text (GTK_ENTRY (details->entry), edit_name);
+ details->conflict_name = g_strdup (conflict_name);
- if (source_is_dir && dest_is_dir) {
- gtk_button_set_label (GTK_BUTTON (details->replace_button),
- _("Merge"));
- }
+ gtk_entry_set_text (GTK_ENTRY (details->entry), details->conflict_name);
- nautilus_file_monitor_add (src, fcd, NAUTILUS_FILE_ATTRIBUTES_FOR_ICON);
- nautilus_file_monitor_add (dest, fcd, NAUTILUS_FILE_ATTRIBUTES_FOR_ICON);
-
- details->src_handler_id = g_signal_connect (src, "changed",
- G_CALLBACK (file_icons_changed), fcd);
- details->dest_handler_id = g_signal_connect (dest, "changed",
- G_CALLBACK (file_icons_changed), fcd);
}
-static void
-build_dialog_appearance (NautilusFileConflictDialog *fcd)
+void
+nautilus_file_conflict_dialog_set_replace_button_label (NautilusFileConflictDialog *fcd,
+ gchar *label)
{
- GList *files = NULL;
- NautilusFileConflictDialogDetails *details = fcd->details;
+ NautilusFileConflictDialogDetails *details = fcd->details;
- files = g_list_prepend (files, details->source);
- files = g_list_prepend (files, details->destination);
- files = g_list_prepend (files, details->dest_dir);
-
- nautilus_file_list_call_when_ready (files,
- NAUTILUS_FILE_ATTRIBUTES_FOR_ICON,
- &details->handle, file_list_ready_cb, fcd);
- g_list_free (files);
+ gtk_button_set_label (GTK_BUTTON (details->replace_button),
+ label);
}
-static void
-set_source_and_destination (GtkWidget *w,
- GFile *source,
- GFile *destination,
- GFile *dest_dir)
+void
+nautilus_file_conflict_dialog_disable_skip (NautilusFileConflictDialog *fcd)
{
- NautilusFileConflictDialog *dialog;
- NautilusFileConflictDialogDetails *details;
+ NautilusFileConflictDialogDetails *details = fcd->details;
- dialog = NAUTILUS_FILE_CONFLICT_DIALOG (w);
- details = dialog->details;
+ gtk_widget_hide (details->skip_button);
+}
- details->source = nautilus_file_get (source);
- details->destination = nautilus_file_get (destination);
- details->dest_dir = nautilus_file_get (dest_dir);
+void
+nautilus_file_conflict_dialog_disable_apply_to_all (NautilusFileConflictDialog *fcd)
+{
+ NautilusFileConflictDialogDetails *details = fcd->details;
- build_dialog_appearance (dialog);
+ gtk_widget_hide (details->checkbox);
}
static void
@@ -549,12 +364,15 @@ nautilus_file_conflict_dialog_init (NautilusFileConflictDialog *fcd)
G_CALLBACK (checkbox_toggled_cb), dialog);
/* Add buttons */
- gtk_dialog_add_buttons (dialog,
- _("_Cancel"),
- GTK_RESPONSE_CANCEL,
- _("_Skip"),
- CONFLICT_RESPONSE_SKIP,
- NULL);
+ gtk_dialog_add_button (dialog,
+ _("_Cancel"),
+ GTK_RESPONSE_CANCEL);
+
+ details->skip_button =
+ gtk_dialog_add_button (dialog,
+ _("_Skip"),
+ CONFLICT_RESPONSE_SKIP);
+
details->rename_button =
gtk_dialog_add_button (dialog,
_("Re_name"),
@@ -583,24 +401,6 @@ do_finalize (GObject *self)
g_free (details->conflict_name);
- if (details->handle != NULL) {
- nautilus_file_list_cancel_call_when_ready (details->handle);
- }
-
- if (details->src_handler_id) {
- g_signal_handler_disconnect (details->source, details->src_handler_id);
- nautilus_file_monitor_remove (details->source, self);
- }
-
- if (details->dest_handler_id) {
- g_signal_handler_disconnect (details->destination, details->dest_handler_id);
- nautilus_file_monitor_remove (details->destination, self);
- }
-
- nautilus_file_unref (details->source);
- nautilus_file_unref (details->destination);
- nautilus_file_unref (details->dest_dir);
-
G_OBJECT_CLASS (nautilus_file_conflict_dialog_parent_class)->finalize (self);
}
@@ -626,45 +426,18 @@ nautilus_file_conflict_dialog_get_apply_to_all (NautilusFileConflictDialog *dial
(GTK_TOGGLE_BUTTON (dialog->details->checkbox));
}
-GtkWidget *
-nautilus_file_conflict_dialog_new (GtkWindow *parent,
- GFile *source,
- GFile *destination,
- GFile *dest_dir)
+NautilusFileConflictDialog *
+nautilus_file_conflict_dialog_new (GtkWindow *parent)
{
- GtkWidget *dialog;
- NautilusFile *src, *dest;
- gboolean source_is_dir, dest_is_dir;
-
- src = nautilus_file_get (source);
- dest = nautilus_file_get (destination);
-
- source_is_dir = nautilus_file_is_directory (src);
- dest_is_dir = nautilus_file_is_directory (dest);
-
- if (source_is_dir) {
- dialog = GTK_WIDGET (g_object_new (NAUTILUS_TYPE_FILE_CONFLICT_DIALOG,
- "use-header-bar", TRUE,
- "modal", TRUE,
- "title", dest_is_dir ? _("Merge Folder") : _("File and Folder conflict"),
- NULL));
- } else {
- dialog = GTK_WIDGET (g_object_new (NAUTILUS_TYPE_FILE_CONFLICT_DIALOG,
- "use-header-bar", TRUE,
- "modal", TRUE,
- "title", dest_is_dir ? _("File and Folder conflict") : _("File conflict"),
- NULL));
- }
-
- set_source_and_destination (dialog,
- source,
- destination,
- dest_dir);
+ NautilusFileConflictDialog *dialog;
+
+ dialog = NAUTILUS_FILE_CONFLICT_DIALOG (g_object_new (NAUTILUS_TYPE_FILE_CONFLICT_DIALOG,
+ "use-header-bar", TRUE,
+ "modal", TRUE,
+ NULL));
+
gtk_window_set_transient_for (GTK_WINDOW (dialog),
parent);
- g_object_unref (src);
- g_object_unref (dest);
-
return dialog;
}
diff --git a/src/nautilus-file-conflict-dialog.h b/src/nautilus-file-conflict-dialog.h
index b7767ce6d..eee92d38f 100644
--- a/src/nautilus-file-conflict-dialog.h
+++ b/src/nautilus-file-conflict-dialog.h
@@ -56,19 +56,27 @@ struct _NautilusFileConflictDialogClass {
GtkDialogClass parent_class;
};
-enum
-{
- CONFLICT_RESPONSE_SKIP = 1,
- CONFLICT_RESPONSE_REPLACE = 2,
- CONFLICT_RESPONSE_RENAME = 3,
-};
-
GType nautilus_file_conflict_dialog_get_type (void) G_GNUC_CONST;
-GtkWidget* nautilus_file_conflict_dialog_new (GtkWindow *parent,
- GFile *source,
- GFile *destination,
- GFile *dest_dir);
+NautilusFileConflictDialog* nautilus_file_conflict_dialog_new (GtkWindow *parent);
+
+void nautilus_file_conflict_dialog_set_text (NautilusFileConflictDialog *fcd,
+ gchar *primary_text,
+ gchar *secondary_text);
+void nautilus_file_conflict_dialog_set_images (NautilusFileConflictDialog *fcd,
+ GdkPixbuf *source_pixbuf,
+ GdkPixbuf *destination_pixbuf);
+void nautilus_file_conflict_dialog_set_file_labels (NautilusFileConflictDialog *fcd,
+ gchar *destination_label,
+ gchar *source_label);
+void nautilus_file_conflict_dialog_set_conflict_name (NautilusFileConflictDialog *fcd,
+ gchar *conflict_name);
+void nautilus_file_conflict_dialog_set_replace_button_label (NautilusFileConflictDialog *fcd,
+ gchar *label);
+
+void nautilus_file_conflict_dialog_disable_skip (NautilusFileConflictDialog *fcd);
+void nautilus_file_conflict_dialog_disable_apply_to_all (NautilusFileConflictDialog *fcd);
+
char* nautilus_file_conflict_dialog_get_new_name (NautilusFileConflictDialog *dialog);
gboolean nautilus_file_conflict_dialog_get_apply_to_all (NautilusFileConflictDialog *dialog);
diff --git a/src/nautilus-file-operations.c b/src/nautilus-file-operations.c
index 804a1c773..518420540 100644
--- a/src/nautilus-file-operations.c
+++ b/src/nautilus-file-operations.c
@@ -51,13 +51,13 @@
#include <gtk/gtk.h>
#include <gio/gio.h>
#include <glib.h>
+#include "nautilus-operations-ui-manager.h"
#include "nautilus-file-changes-queue.h"
#include "nautilus-file-private.h"
#include "nautilus-global-preferences.h"
#include "nautilus-link.h"
#include "nautilus-trash-monitor.h"
#include "nautilus-file-utilities.h"
-#include "nautilus-file-conflict-dialog.h"
#include "nautilus-file-undo-operations.h"
#include "nautilus-file-undo-manager.h"
@@ -4292,117 +4292,26 @@ is_trusted_desktop_file (GFile *file,
return res;
}
-typedef struct {
- int id;
- char *new_name;
- gboolean apply_to_all;
-} ConflictResponseData;
-
-typedef struct {
- GFile *src;
- GFile *dest;
- GFile *dest_dir;
- GtkWindow *parent;
- ConflictResponseData *resp_data;
- /* Dialogs are ran from operation threads, which need to be blocked until
- * the user gives a valid response
- */
- gboolean completed;
- GMutex mutex;
- GCond cond;
-} ConflictDialogData;
-
-static gboolean
-do_run_conflict_dialog (gpointer _data)
-{
- ConflictDialogData *data = _data;
- GtkWidget *dialog;
- int response;
-
- g_mutex_lock (&data->mutex);
-
- dialog = nautilus_file_conflict_dialog_new (data->parent,
- data->src,
- data->dest,
- data->dest_dir);
- response = gtk_dialog_run (GTK_DIALOG (dialog));
-
- if (response == CONFLICT_RESPONSE_RENAME) {
- data->resp_data->new_name =
- nautilus_file_conflict_dialog_get_new_name (NAUTILUS_FILE_CONFLICT_DIALOG (dialog));
- } else if (response != GTK_RESPONSE_CANCEL &&
- response != GTK_RESPONSE_NONE) {
- data->resp_data->apply_to_all =
- nautilus_file_conflict_dialog_get_apply_to_all
- (NAUTILUS_FILE_CONFLICT_DIALOG (dialog));
- }
-
- data->resp_data->id = response;
- data->completed = TRUE;
-
- gtk_widget_destroy (dialog);
-
- g_cond_signal (&data->cond);
- g_mutex_unlock (&data->mutex);
-
- return FALSE;
-}
-
-static ConflictResponseData *
-run_conflict_dialog (CommonJob *job,
- GFile *src,
- GFile *dest,
- GFile *dest_dir)
+static FileConflictResponse *
+handle_copy_move_conflict (CommonJob *job,
+ GFile *src,
+ GFile *dest,
+ GFile *dest_dir)
{
- ConflictDialogData *data;
- ConflictResponseData *resp_data;
-
- g_timer_stop (job->time);
-
- data = g_slice_new0 (ConflictDialogData);
- data->parent = job->parent_window;
- data->src = src;
- data->dest = dest;
- data->dest_dir = dest_dir;
-
- resp_data = g_slice_new0 (ConflictResponseData);
- resp_data->new_name = NULL;
- data->resp_data = resp_data;
-
- data->completed = FALSE;
- g_mutex_init (&data->mutex);
- g_cond_init (&data->cond);
+ FileConflictResponse *response;
- nautilus_progress_info_pause (job->progress);
+ g_timer_stop (job->time);
+ nautilus_progress_info_pause (job->progress);
- g_mutex_lock (&data->mutex);
+ response = copy_move_conflict_ask_user_action (job->parent_window,
+ src,
+ dest,
+ dest_dir);
- g_main_context_invoke (NULL,
- do_run_conflict_dialog,
- data);
+ nautilus_progress_info_resume (job->progress);
+ g_timer_continue (job->time);
- while (!data->completed) {
- g_cond_wait (&data->cond, &data->mutex);
- }
-
- nautilus_progress_info_resume (job->progress);
-
- g_mutex_unlock (&data->mutex);
- g_mutex_clear (&data->mutex);
- g_cond_clear (&data->cond);
-
- g_slice_free (ConflictDialogData, data);
-
- g_timer_continue (job->time);
-
- return resp_data;
-}
-
-static void
-conflict_response_data_free (ConflictResponseData *data)
-{
- g_free (data->new_name);
- g_slice_free (ConflictResponseData, data);
+ return response;
}
static GFile *
@@ -4649,7 +4558,7 @@ copy_move_file (CopyMoveJob *copy_job,
if (!overwrite &&
IS_IO_ERROR (error, EXISTS)) {
gboolean is_merge;
- ConflictResponseData *response;
+ FileConflictResponse *response;
g_error_free (error);
@@ -4675,17 +4584,17 @@ copy_move_file (CopyMoveJob *copy_job,
goto out;
}
- response = run_conflict_dialog (job, src, dest, dest_dir);
+ response = handle_copy_move_conflict (job, src, dest, dest_dir);
if (response->id == GTK_RESPONSE_CANCEL ||
response->id == GTK_RESPONSE_DELETE_EVENT) {
- conflict_response_data_free (response);
+ file_conflict_response_free (response);
abort_job (job);
} else if (response->id == CONFLICT_RESPONSE_SKIP) {
if (response->apply_to_all) {
job->skip_all_conflict = TRUE;
}
- conflict_response_data_free (response);
+ file_conflict_response_free (response);
} else if (response->id == CONFLICT_RESPONSE_REPLACE) { /* merge/replace */
if (response->apply_to_all) {
if (is_merge) {
@@ -4695,13 +4604,13 @@ copy_move_file (CopyMoveJob *copy_job,
}
}
overwrite = TRUE;
- conflict_response_data_free (response);
+ file_conflict_response_free (response);
goto retry;
} else if (response->id == CONFLICT_RESPONSE_RENAME) {
g_object_unref (dest);
dest = get_target_file_for_display_name (dest_dir,
response->new_name);
- conflict_response_data_free (response);
+ file_conflict_response_free (response);
goto retry;
} else {
g_assert_not_reached ();
@@ -5292,7 +5201,7 @@ move_file_prepare (CopyMoveJob *move_job,
else if (!overwrite &&
IS_IO_ERROR (error, EXISTS)) {
gboolean is_merge;
- ConflictResponseData *response;
+ FileConflictResponse *response;
g_error_free (error);
@@ -5311,17 +5220,17 @@ move_file_prepare (CopyMoveJob *move_job,
goto out;
}
- response = run_conflict_dialog (job, src, dest, dest_dir);
+ response = handle_copy_move_conflict (job, src, dest, dest_dir);
if (response->id == GTK_RESPONSE_CANCEL ||
response->id == GTK_RESPONSE_DELETE_EVENT) {
- conflict_response_data_free (response);
+ file_conflict_response_free (response);
abort_job (job);
} else if (response->id == CONFLICT_RESPONSE_SKIP) {
if (response->apply_to_all) {
job->skip_all_conflict = TRUE;
}
- conflict_response_data_free (response);
+ file_conflict_response_free (response);
} else if (response->id == CONFLICT_RESPONSE_REPLACE) { /* merge/replace */
if (response->apply_to_all) {
if (is_merge) {
@@ -5331,13 +5240,13 @@ move_file_prepare (CopyMoveJob *move_job,
}
}
overwrite = TRUE;
- conflict_response_data_free (response);
+ file_conflict_response_free (response);
goto retry;
} else if (response->id == CONFLICT_RESPONSE_RENAME) {
g_object_unref (dest);
dest = get_target_file_for_display_name (dest_dir,
response->new_name);
- conflict_response_data_free (response);
+ file_conflict_response_free (response);
goto retry;
} else {
g_assert_not_reached ();
diff --git a/src/nautilus-operations-ui-manager.c b/src/nautilus-operations-ui-manager.c
new file mode 100644
index 000000000..022c8ccc0
--- /dev/null
+++ b/src/nautilus-operations-ui-manager.c
@@ -0,0 +1,449 @@
+#include <glib/gi18n.h>
+
+#include "nautilus-operations-ui-manager.h"
+
+#include "nautilus-file.h"
+#include "nautilus-file-operations.h"
+#include "nautilus-file-conflict-dialog.h"
+
+typedef struct {
+ GSourceFunc source_func;
+ gpointer user_data;
+ GMutex mutex;
+ GCond cond;
+ gboolean completed;
+} ContextInvokeData;
+
+G_LOCK_DEFINE_STATIC (main_context_sync);
+
+static gboolean
+invoke_main_context_source_func_wrapper (gpointer user_data)
+{
+ ContextInvokeData *data = user_data;
+
+ g_mutex_lock (&data->mutex);
+
+ while (data->source_func (data->user_data));
+
+ data->completed = TRUE;
+
+ g_cond_signal (&data->cond);
+ g_mutex_unlock (&data->mutex);
+
+ return G_SOURCE_REMOVE;
+}
+
+/* This function is used to run UI on the main thread in order to ask the user
+ * for an action during an operation. Since the operation cannot progress until
+ * an action is provided by the user, the current thread needs to be blocked.
+ * For this we wait on a condition on the shared data. We proceed further
+ * unblocking the thread when the condition is set in the UI thread.
+ */
+static void
+invoke_main_context_sync (GMainContext *main_context,
+ GSourceFunc source_func,
+ gpointer user_data)
+{
+ ContextInvokeData data;
+ /* Allow only one thread at a time to invoke the main context so we
+ * don't get race conditions which could lead to multiple dialogs being
+ * displayed at the same time
+ */
+ G_LOCK (main_context_sync);
+
+ data.source_func = source_func;
+ data.user_data = user_data;
+
+ g_mutex_init (&data.mutex);
+ g_cond_init (&data.cond);
+ data.completed = FALSE;
+
+ g_mutex_lock (&data.mutex);
+
+ g_main_context_invoke (main_context,
+ invoke_main_context_source_func_wrapper,
+ &data);
+
+ while (!data.completed) {
+ g_cond_wait (&data.cond, &data.mutex);
+ }
+
+ g_mutex_unlock (&data.mutex);
+
+ G_UNLOCK (main_context_sync);
+
+ g_mutex_clear (&data.mutex);
+ g_cond_clear (&data.cond);
+}
+
+typedef struct {
+ GFile *source_name;
+ GFile *destination_name;
+ GFile *destination_directory_name;
+
+ GtkWindow *parent;
+
+ FileConflictResponse *response;
+
+ NautilusFile *source;
+ NautilusFile *destination;
+ NautilusFile *destination_directory;
+
+ NautilusFileConflictDialog *dialog;
+
+ NautilusFileListCallback on_file_list_ready;
+ NautilusFileListHandle *handle;
+ gulong source_handler_id;
+ gulong destination_handler_id;
+} FileConflictDialogData;
+
+void
+file_conflict_response_free (FileConflictResponse *response)
+{
+ g_free (response->new_name);
+ g_slice_free (FileConflictResponse, response);
+}
+
+static void
+set_copy_move_dialog_text (FileConflictDialogData *data)
+{
+ g_autofree gchar *primary_text = NULL;
+ g_autofree gchar *secondary_text = NULL;
+ const gchar *message_extra;
+ time_t source_mtime;
+ time_t destination_mtime;
+ g_autofree gchar *message = NULL;
+ g_autofree gchar *destination_name;
+ g_autofree gchar *destination_directory_name;
+ gboolean source_is_directory;
+ gboolean destination_is_directory;
+
+ source_mtime = nautilus_file_get_mtime (data->source);
+ destination_mtime = nautilus_file_get_mtime (data->destination);
+
+ destination_name = nautilus_file_get_display_name (data->destination);
+ destination_directory_name = nautilus_file_get_display_name (data->destination_directory);
+
+ source_is_directory = nautilus_file_is_directory (data->source);
+ destination_is_directory = nautilus_file_is_directory (data->destination);
+
+ if (destination_is_directory) {
+ if (source_is_directory) {
+ primary_text = g_strdup_printf (_("Merge folder “%s”?"),
+ destination_name);
+
+ message_extra = _("Merging will ask for confirmation before replacing any files in "
+ "the folder that conflict with the files being copied.");
+
+ if (source_mtime > destination_mtime) {
+ message = g_strdup_printf (_("An older folder with the same name already exists in “%s”."),
+ destination_directory_name);
+ } else if (source_mtime < destination_mtime) {
+ message = g_strdup_printf (_("A newer folder with the same name already exists in “%s”."),
+ destination_directory_name);
+ } else {
+ message = g_strdup_printf (_("Another folder with the same name already exists in “%s”."),
+ destination_directory_name);
+ }
+ } else {
+ primary_text = g_strdup_printf (_("Replace folder “%s”?"),
+ destination_name);
+ message_extra = _("Replacing it will remove all files in the folder.");
+ message = g_strdup_printf (_("A folder with the same name already exists in “%s”."),
+ destination_directory_name);
+ }
+ } else {
+ primary_text = g_strdup_printf (_("Replace file “%s”?"),
+ destination_name);
+
+ message_extra = _("Replacing it will overwrite its content.");
+
+ if (source_mtime > destination_mtime) {
+ message = g_strdup_printf (_("An older file with the same name already exists in “%s”."),
+ destination_directory_name);
+ } else if (source_mtime < destination_mtime) {
+ message = g_strdup_printf (_("A newer file with the same name already exists in “%s”."),
+ destination_directory_name);
+ } else {
+ message = g_strdup_printf (_("Another file with the same name already exists in “%s”."),
+ destination_directory_name);
+ }
+ }
+
+ secondary_text = g_strdup_printf ("%s\n%s", message, message_extra);
+
+ nautilus_file_conflict_dialog_set_text (data->dialog,
+ primary_text,
+ secondary_text);
+}
+
+static void
+set_images (FileConflictDialogData *data)
+{
+ GdkPixbuf *source_pixbuf;
+ GdkPixbuf *destination_pixbuf;
+
+ destination_pixbuf = nautilus_file_get_icon_pixbuf (data->destination,
+ NAUTILUS_CANVAS_ICON_SIZE_SMALL,
+ TRUE,
+ 1,
+ NAUTILUS_FILE_ICON_FLAGS_USE_THUMBNAILS);
+
+ source_pixbuf = nautilus_file_get_icon_pixbuf (data->source,
+ NAUTILUS_CANVAS_ICON_SIZE_SMALL,
+ TRUE,
+ 1,
+ NAUTILUS_FILE_ICON_FLAGS_USE_THUMBNAILS);
+
+ nautilus_file_conflict_dialog_set_images (data->dialog,
+ destination_pixbuf,
+ source_pixbuf);
+
+ g_object_unref (destination_pixbuf);
+ g_object_unref (source_pixbuf);
+}
+
+static void
+set_file_labels (FileConflictDialogData *data)
+{
+ GString *destination_label;
+ GString *source_label;
+ gboolean source_is_directory;
+ gboolean destination_is_directory;
+ gboolean should_show_type;
+ g_autofree char *destination_mime_type = NULL;
+ g_autofree char *destination_date = NULL;
+ g_autofree char *destination_size = NULL;
+ g_autofree char *destination_type = NULL;
+ g_autofree char *source_date = NULL;
+ g_autofree char *source_size = NULL;
+ g_autofree char *source_type = NULL;
+
+ source_is_directory = nautilus_file_is_directory (data->source);
+ destination_is_directory = nautilus_file_is_directory (data->destination);
+
+ destination_mime_type = nautilus_file_get_mime_type (data->destination);
+ should_show_type = !nautilus_file_is_mime_type (data->source,
+ destination_mime_type);
+
+ destination_date = nautilus_file_get_string_attribute (data->destination,
+ "date_modified");
+ destination_size = nautilus_file_get_string_attribute (data->destination,
+ "size");
+
+ if (should_show_type) {
+ destination_type = nautilus_file_get_string_attribute (data->destination,
+ "type");
+ }
+
+ destination_label = g_string_new (NULL);
+ if (destination_is_directory) {
+ g_string_append_printf (destination_label, "<b>%s</b>\n", _("Original folder"));
+ g_string_append_printf (destination_label, "%s %s\n", _("Items:"), destination_size);
+ }
+ else {
+ g_string_append_printf (destination_label, "<b>%s</b>\n", _("Original file"));
+ g_string_append_printf (destination_label, "%s %s\n", _("Size:"), destination_size);
+ }
+
+ if (should_show_type) {
+ g_string_append_printf (destination_label, "%s %s\n", _("Type:"), destination_type);
+ }
+
+ g_string_append_printf (destination_label, "%s %s", _("Last modified:"), destination_date);
+
+ source_date = nautilus_file_get_string_attribute (data->source,
+ "date_modified");
+ source_size = nautilus_file_get_string_attribute (data->source,
+ "size");
+
+ if (should_show_type) {
+ source_type = nautilus_file_get_string_attribute (data->source,
+ "type");
+ }
+
+ source_label = g_string_new (NULL);
+ if (source_is_directory) {
+ g_string_append_printf (source_label, "<b>%s</b>\n",
+ destination_is_directory ?
+ _("Merge with") : _("Replace with"));
+ g_string_append_printf (source_label, "%s %s\n", _("Items:"), source_size);
+ }
+ else {
+ g_string_append_printf (source_label, "<b>%s</b>\n", _("Replace with"));
+ g_string_append_printf (source_label, "%s %s\n", _("Size:"), source_size);
+ }
+
+ if (should_show_type) {
+ g_string_append_printf (source_label, "%s %s\n", _("Type:"), source_type);
+ }
+
+ g_string_append_printf (source_label, "%s %s", _("Last modified:"), source_date);
+
+ nautilus_file_conflict_dialog_set_file_labels (data->dialog,
+ destination_label->str,
+ source_label->str);
+
+ g_string_free (destination_label, TRUE);
+ g_string_free (source_label, TRUE);
+}
+
+static void
+set_conflict_name (FileConflictDialogData *data)
+{
+ g_autofree gchar *edit_name;
+
+ edit_name = nautilus_file_get_edit_name (data->destination);
+
+ nautilus_file_conflict_dialog_set_conflict_name (data->dialog,
+ edit_name);
+}
+
+static void
+set_replace_button_label (FileConflictDialogData *data)
+{
+ gboolean source_is_directory, destination_is_directory;
+
+ source_is_directory = nautilus_file_is_directory (data->source);
+ destination_is_directory = nautilus_file_is_directory (data->destination);
+
+ if (source_is_directory && destination_is_directory) {
+ nautilus_file_conflict_dialog_set_replace_button_label (data->dialog,
+ _("Merge"));
+ }
+}
+
+static void
+file_icons_changed (NautilusFile *file,
+ FileConflictDialogData *data)
+{
+ set_images (data);
+}
+
+static void
+copy_move_conflict_on_file_list_ready (GList *files,
+ gpointer user_data)
+{
+ FileConflictDialogData *data = user_data;
+ g_autofree gchar *title;
+
+ data->handle = NULL;
+
+ if (nautilus_file_is_directory (data->source)) {
+ title = g_strdup (nautilus_file_is_directory (data->destination) ?
+ _("Merge Folder") :
+ _("File and Folder conflict"));
+ } else {
+ title = g_strdup (nautilus_file_is_directory (data->destination) ?
+ _("File and Folder conflict") :
+ _("File conflict"));
+ }
+
+ gtk_window_set_title (GTK_WINDOW (data->dialog), title);
+
+ set_copy_move_dialog_text (data);
+
+ set_images (data);
+
+ set_file_labels (data);
+
+ set_conflict_name (data);
+
+ set_replace_button_label (data);
+
+ nautilus_file_monitor_add (data->source, data, NAUTILUS_FILE_ATTRIBUTES_FOR_ICON);
+ nautilus_file_monitor_add (data->destination, data, NAUTILUS_FILE_ATTRIBUTES_FOR_ICON);
+
+ data->source_handler_id = g_signal_connect (data->source, "changed",
+ G_CALLBACK (file_icons_changed), data);
+ data->destination_handler_id = g_signal_connect (data->destination, "changed",
+ G_CALLBACK (file_icons_changed), data);
+}
+
+static gboolean
+run_file_conflict_dialog (gpointer user_data)
+{
+ FileConflictDialogData *data = user_data;
+ int response_id;
+ GList *files = NULL;
+
+ data->source = nautilus_file_get (data->source_name);
+ data->destination = nautilus_file_get (data->destination_name);
+ data->destination_directory = nautilus_file_get (data->destination_directory_name);
+
+ data->dialog = nautilus_file_conflict_dialog_new (data->parent);
+
+ files = g_list_prepend (files, data->source);
+ files = g_list_prepend (files, data->destination);
+ files = g_list_prepend (files, data->destination_directory);
+
+ nautilus_file_list_call_when_ready (files,
+ NAUTILUS_FILE_ATTRIBUTES_FOR_ICON,
+ &data->handle,
+ data->on_file_list_ready,
+ data);
+
+ response_id = gtk_dialog_run (GTK_DIALOG (data->dialog));
+
+ if (data->handle != NULL) {
+ nautilus_file_list_cancel_call_when_ready (data->handle);
+ }
+
+ if (data->source_handler_id) {
+ g_signal_handler_disconnect (data->source, data->source_handler_id);
+ nautilus_file_monitor_remove (data->source, data);
+ }
+
+ if (data->destination_handler_id) {
+ g_signal_handler_disconnect (data->destination, data->destination_handler_id);
+ nautilus_file_monitor_remove (data->destination, data);
+ }
+
+ if (response_id == CONFLICT_RESPONSE_RENAME) {
+ data->response->new_name =
+ nautilus_file_conflict_dialog_get_new_name (data->dialog);
+ } else if (response_id != GTK_RESPONSE_CANCEL ||
+ response_id != GTK_RESPONSE_NONE) {
+ data->response->apply_to_all =
+ nautilus_file_conflict_dialog_get_apply_to_all (data->dialog);
+ }
+
+ data->response->id = response_id;
+
+ gtk_widget_destroy (GTK_WIDGET (data->dialog));
+
+ nautilus_file_unref (data->source);
+ nautilus_file_unref (data->destination);
+ nautilus_file_unref (data->destination_directory);
+ g_list_free (files);
+
+ return G_SOURCE_REMOVE;
+}
+
+FileConflictResponse *
+copy_move_conflict_ask_user_action (GtkWindow *parent_window,
+ GFile *source_name,
+ GFile *destination_name,
+ GFile *destination_directory_name)
+{
+ FileConflictDialogData *data;
+
+ data = g_slice_new0 (FileConflictDialogData);
+ data->parent = parent_window;
+ data->source_name = source_name;
+ data->destination_name = destination_name;
+ data->destination_directory_name = destination_directory_name;
+
+ data->response = g_slice_new0 (FileConflictResponse);
+ data->response->new_name = NULL;
+
+ data->on_file_list_ready = copy_move_conflict_on_file_list_ready;
+
+ invoke_main_context_sync (NULL,
+ run_file_conflict_dialog,
+ data);
+
+ g_slice_free (FileConflictDialogData, data);
+
+ return data->response;
+}
diff --git a/src/nautilus-operations-ui-manager.h b/src/nautilus-operations-ui-manager.h
new file mode 100644
index 000000000..8c9102c74
--- /dev/null
+++ b/src/nautilus-operations-ui-manager.h
@@ -0,0 +1,27 @@
+#ifndef NAUTILUS_OPERATIONS_UI_MANAGER
+#define NAUTILUS_OPERATIONS_UI_MANAGER
+
+#include <gio/gio.h>
+#include <gtk/gtk.h>
+
+typedef struct {
+ int id;
+ char *new_name;
+ gboolean apply_to_all;
+} FileConflictResponse;
+
+void file_conflict_response_free (FileConflictResponse *data);
+
+FileConflictResponse * copy_move_conflict_ask_user_action (GtkWindow *parent_window,
+ GFile *src,
+ GFile *dest,
+ GFile *dest_dir);
+
+enum
+{
+ CONFLICT_RESPONSE_SKIP = 1,
+ CONFLICT_RESPONSE_REPLACE = 2,
+ CONFLICT_RESPONSE_RENAME = 3,
+};
+
+#endif /* NAUTILUS_OPERATIONS_UI_MANAGER */