1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2 
3 /* caja-file-conflict-dialog: dialog that handles file conflicts
4    during transfer operations.
5 
6    Copyright (C) 2008-2010 Cosimo Cecchi
7 
8    This program is free software; you can redistribute it and/or
9    modify it under the terms of the GNU General Public License as
10    published by the Free Software Foundation; either version 2 of the
11    License, or (at your option) any later version.
12 
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16    General Public License for more details.
17 
18    You should have received a copy of the GNU General Public
19    License along with this program; if not, write to the
20    Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
21    Boston, MA 02110-1301, USA.
22 
23    Authors: Cosimo Cecchi <cosimoc@gnome.org>
24 */
25 
26 #include <config.h>
27 #include <string.h>
28 #include <glib-object.h>
29 #include <gio/gio.h>
30 #include <glib/gi18n.h>
31 #include <pango/pango.h>
32 
33 #include <eel/eel-vfs-extensions.h>
34 #include <eel/eel-stock-dialogs.h>
35 
36 #include "caja-file-conflict-dialog.h"
37 #include "caja-file.h"
38 #include "caja-icon-info.h"
39 
40 struct _CajaFileConflictDialogPrivate
41 {
42     /* conflicting objects */
43     CajaFile *source;
44     CajaFile *destination;
45     CajaFile *dest_dir;
46 
47     gchar *conflict_name;
48     CajaFileListHandle *handle;
49     gulong src_handler_id;
50     gulong dest_handler_id;
51 
52     /* UI objects */
53     GtkWidget *titles_vbox;
54     GtkWidget *first_hbox;
55     GtkWidget *second_hbox;
56     GtkWidget *expander;
57     GtkWidget *entry;
58     GtkWidget *checkbox;
59     GtkWidget *rename_button;
60     GtkWidget *diff_button;
61     GtkWidget *replace_button;
62     GtkWidget *dest_image;
63     GtkWidget *src_image;
64 };
65 
66 G_DEFINE_TYPE_WITH_PRIVATE (CajaFileConflictDialog,
67                             caja_file_conflict_dialog,
68                             GTK_TYPE_DIALOG);
69 
70 static void
file_icons_changed(CajaFile * file,CajaFileConflictDialog * fcd)71 file_icons_changed (CajaFile *file,
72                     CajaFileConflictDialog *fcd)
73 {
74     cairo_surface_t *surface;
75 
76     surface = caja_file_get_icon_surface (fcd->details->destination,
77                                           CAJA_ICON_SIZE_LARGE,
78                                           FALSE,
79                                           gtk_widget_get_scale_factor (fcd->details->dest_image),
80                                           CAJA_FILE_ICON_FLAGS_USE_THUMBNAILS);
81 
82     gtk_image_set_from_surface (GTK_IMAGE (fcd->details->dest_image), surface);
83     cairo_surface_destroy (surface);
84 
85     surface = caja_file_get_icon_surface (fcd->details->source,
86                                           CAJA_ICON_SIZE_LARGE,
87                                           FALSE,
88                                           gtk_widget_get_scale_factor (fcd->details->src_image),
89                                           CAJA_FILE_ICON_FLAGS_USE_THUMBNAILS);
90 
91     gtk_image_set_from_surface (GTK_IMAGE (fcd->details->src_image), surface);
92     cairo_surface_destroy (surface);
93 }
94 
95 static void
file_list_ready_cb(GList * files,gpointer user_data)96 file_list_ready_cb (GList *files,
97                     gpointer user_data)
98 {
99     CajaFileConflictDialog *fcd = user_data;
100     CajaFile *src, *dest, *dest_dir;
101     time_t src_mtime, dest_mtime;
102     gboolean source_is_dir,	dest_is_dir, should_show_type;
103     CajaFileConflictDialogPrivate *details;
104     char *primary_text, *message, *secondary_text;
105     const gchar *message_extra;
106     char *dest_name, *dest_dir_name, *edit_name;
107     char *label_text;
108     char *size, *date, *type = NULL;
109     cairo_surface_t *surface;
110     GtkWidget *label;
111     GString *str;
112     PangoAttrList *attr_list;
113 
114     details = fcd->details;
115 
116     details->handle = NULL;
117 
118     dest_dir = g_list_nth_data (files, 0);
119     dest = g_list_nth_data (files, 1);
120     src = g_list_nth_data (files, 2);
121 
122     src_mtime = caja_file_get_mtime (src);
123     dest_mtime = caja_file_get_mtime (dest);
124 
125     dest_name = caja_file_get_display_name (dest);
126     dest_dir_name = caja_file_get_display_name (dest_dir);
127 
128     source_is_dir = caja_file_is_directory (src);
129     dest_is_dir = caja_file_is_directory (dest);
130 
131     type = caja_file_get_mime_type (dest);
132     should_show_type = !caja_file_is_mime_type (src, type);
133 
134     g_free (type);
135     type = NULL;
136 
137     /* Set up the right labels */
138     if (dest_is_dir)
139     {
140         if (source_is_dir)
141         {
142             primary_text = g_strdup_printf
143                            (_("Merge folder \"%s\"?"),
144                             dest_name);
145 
146             message_extra =
147                 _("Merging will ask for confirmation before replacing any files in "
148                   "the folder that conflict with the files being copied.");
149 
150             if (src_mtime > dest_mtime)
151             {
152                 message = g_strdup_printf (
153                               _("An older folder with the same name already exists in \"%s\"."),
154                               dest_dir_name);
155             }
156             else if (src_mtime < dest_mtime)
157             {
158                 message = g_strdup_printf (
159                               _("A newer folder with the same name already exists in \"%s\"."),
160                               dest_dir_name);
161             }
162             else
163             {
164                 message = g_strdup_printf (
165                               _("Another folder with the same name already exists in \"%s\"."),
166                               dest_dir_name);
167             }
168         }
169         else
170         {
171             message_extra =
172                 _("Replacing it will remove all files in the folder.");
173             primary_text = g_strdup_printf
174                            (_("Replace folder \"%s\"?"), dest_name);
175             message = g_strdup_printf
176                       (_("A folder with the same name already exists in \"%s\"."),
177                        dest_dir_name);
178         }
179     }
180     else
181     {
182         primary_text = g_strdup_printf
183                        (_("Replace file \"%s\"?"), dest_name);
184 
185         message_extra = _("Replacing it will overwrite its content.");
186 
187         if (src_mtime > dest_mtime)
188         {
189             message = g_strdup_printf (
190                           _("An older file with the same name already exists in \"%s\"."),
191                           dest_dir_name);
192         }
193         else if (src_mtime < dest_mtime)
194         {
195             message = g_strdup_printf (
196                           _("A newer file with the same name already exists in \"%s\"."),
197                           dest_dir_name);
198         }
199         else
200         {
201             message = g_strdup_printf (
202                           _("Another file with the same name already exists in \"%s\"."),
203                           dest_dir_name);
204         }
205     }
206 
207     secondary_text = g_strdup_printf ("%s\n%s", message, message_extra);
208     g_free (message);
209 
210     label = gtk_label_new (primary_text);
211     gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
212     gtk_label_set_line_wrap_mode (GTK_LABEL (label), PANGO_WRAP_WORD_CHAR);
213     gtk_label_set_xalign (GTK_LABEL (label), 0.0);
214     gtk_box_pack_start (GTK_BOX (details->titles_vbox),
215                         label, FALSE, FALSE, 0);
216     gtk_widget_show (label);
217 
218     attr_list = pango_attr_list_new ();
219     pango_attr_list_insert (attr_list, pango_attr_weight_new (PANGO_WEIGHT_BOLD));
220     pango_attr_list_insert (attr_list, pango_attr_scale_new (PANGO_SCALE_LARGE));
221     g_object_set (label,
222                   "attributes", attr_list,
223                   NULL);
224 
225     pango_attr_list_unref (attr_list);
226     label = gtk_label_new (secondary_text);
227     gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
228     gtk_label_set_max_width_chars (GTK_LABEL (label), 60);
229     gtk_label_set_xalign (GTK_LABEL (label), 0.0);
230     gtk_box_pack_start (GTK_BOX (details->titles_vbox),
231                         label, FALSE, FALSE, 0);
232     gtk_widget_show (label);
233     g_free (primary_text);
234     g_free (secondary_text);
235 
236     /* Set up file icons */
237     surface = caja_file_get_icon_surface (dest,
238                                           CAJA_ICON_SIZE_LARGE,
239                                           TRUE,
240                                           gtk_widget_get_scale_factor (fcd->details->titles_vbox),
241                                           CAJA_FILE_ICON_FLAGS_USE_THUMBNAILS);
242     details->dest_image = gtk_image_new_from_surface (surface);
243     gtk_box_pack_start (GTK_BOX (details->first_hbox),
244                         details->dest_image, FALSE, FALSE, 0);
245     gtk_widget_show (details->dest_image);
246     cairo_surface_destroy (surface);
247 
248     surface = caja_file_get_icon_surface (src,
249                                           CAJA_ICON_SIZE_LARGE,
250                                           TRUE,
251                                           gtk_widget_get_scale_factor (fcd->details->titles_vbox),
252                                           CAJA_FILE_ICON_FLAGS_USE_THUMBNAILS);
253     details->src_image = gtk_image_new_from_surface (surface);
254     gtk_box_pack_start (GTK_BOX (details->second_hbox),
255                         details->src_image, FALSE, FALSE, 0);
256     gtk_widget_show (details->src_image);
257     cairo_surface_destroy (surface);
258 
259     /* Set up labels */
260     label = gtk_label_new (NULL);
261     date = caja_file_get_string_attribute (dest,
262                                            "date_modified");
263     size = caja_file_get_string_attribute (dest, "size");
264 
265     if (should_show_type)
266     {
267         type = caja_file_get_string_attribute (dest, "type");
268     }
269 
270     str = g_string_new (NULL);
271     if (dest_is_dir) {
272         g_string_append_printf (str, "<b>%s</b>\n", _("Original folder"));
273         g_string_append_printf (str, "%s %s\n", _("Items:"), size);
274     }
275     else {
276         g_string_append_printf (str, "<b>%s</b>\n", _("Original file"));
277         g_string_append_printf (str, "%s %s\n", _("Size:"), size);
278     }
279 
280     if (should_show_type)
281     {
282         g_string_append_printf (str, "%s %s\n", _("Type:"), type);
283     }
284 
285     g_string_append_printf (str, "%s %s", _("Last modified:"), date);
286 
287     label_text = str->str;
288     gtk_label_set_markup (GTK_LABEL (label),
289                           label_text);
290     gtk_box_pack_start (GTK_BOX (details->first_hbox),
291                         label, FALSE, FALSE, 0);
292     gtk_widget_show (label);
293 
294     g_free (size);
295     g_free (type);
296     g_free (date);
297     g_string_erase (str, 0, -1);
298 
299     /* Second label */
300     label = gtk_label_new (NULL);
301     date = caja_file_get_string_attribute (src,
302                                            "date_modified");
303     size = caja_file_get_string_attribute (src, "size");
304 
305     if (should_show_type)
306     {
307         type = caja_file_get_string_attribute (src, "type");
308     }
309 
310     if (source_is_dir) {
311         g_string_append_printf (str, "<b>%s</b>\n", dest_is_dir ? _("Merge with") : _("Replace with"));
312         g_string_append_printf (str, "%s %s\n", _("Items:"), size);
313     }
314     else {
315         g_string_append_printf (str, "<b>%s</b>\n", _("Replace with"));
316         g_string_append_printf (str, "%s %s\n", _("Size:"), size);
317     }
318 
319     if (should_show_type)
320     {
321         g_string_append_printf (str, "%s %s\n", _("Type:"), type);
322     }
323 
324     g_string_append_printf (str, "%s %s", _("Last modified:"), date);
325     label_text = g_string_free (str, FALSE);
326 
327     gtk_label_set_markup (GTK_LABEL (label),
328                           label_text);
329     gtk_box_pack_start (GTK_BOX (details->second_hbox),
330                         label, FALSE, FALSE, 0);
331     gtk_widget_show (label);
332 
333     g_free (size);
334     g_free (date);
335     g_free (type);
336     g_free (label_text);
337 
338     /* Populate the entry */
339     edit_name = caja_file_get_edit_name (dest);
340     details->conflict_name = edit_name;
341 
342     gtk_entry_set_text (GTK_ENTRY (details->entry), edit_name);
343 
344     if (source_is_dir && dest_is_dir)
345     {
346         gtk_button_set_label (GTK_BUTTON (details->replace_button),
347                               _("Merge"));
348     }
349 
350     /* If meld is installed, and source and destination arent binary
351      * files, show the diff button
352      */
353     gtk_widget_hide (details->diff_button);
354     if (!source_is_dir && !dest_is_dir)
355     {
356         gchar *meld_found = g_find_program_in_path ("meld");
357         if (meld_found) {
358             g_free (meld_found);
359             gboolean src_is_binary;
360             gboolean dest_is_binary;
361 
362             src_is_binary = caja_file_is_binary (details->source);
363             dest_is_binary = caja_file_is_binary (details->destination);
364 
365             if (!src_is_binary && !dest_is_binary)
366                 gtk_widget_show (details->diff_button);
367         }
368     }
369 
370     caja_file_monitor_add (src, fcd, CAJA_FILE_ATTRIBUTES_FOR_ICON);
371     caja_file_monitor_add (dest, fcd, CAJA_FILE_ATTRIBUTES_FOR_ICON);
372 
373     details->src_handler_id = g_signal_connect (src, "changed",
374                               G_CALLBACK (file_icons_changed), fcd);
375     details->dest_handler_id = g_signal_connect (dest, "changed",
376                                G_CALLBACK (file_icons_changed), fcd);
377 }
378 
379 static void
build_dialog_appearance(CajaFileConflictDialog * fcd)380 build_dialog_appearance (CajaFileConflictDialog *fcd)
381 {
382     GList *files = NULL;
383     CajaFileConflictDialogPrivate *details = fcd->details;
384 
385     files = g_list_prepend (files, details->source);
386     files = g_list_prepend (files, details->destination);
387     files = g_list_prepend (files, details->dest_dir);
388 
389     caja_file_list_call_when_ready (files,
390                                     CAJA_FILE_ATTRIBUTES_FOR_ICON,
391                                     &details->handle, file_list_ready_cb, fcd);
392     g_list_free (files);
393 }
394 
395 static void
set_source_and_destination(GtkWidget * w,GFile * source,GFile * destination,GFile * dest_dir)396 set_source_and_destination (GtkWidget *w,
397                             GFile *source,
398                             GFile *destination,
399                             GFile *dest_dir)
400 {
401     CajaFileConflictDialog *dialog;
402     CajaFileConflictDialogPrivate *details;
403 
404     dialog = CAJA_FILE_CONFLICT_DIALOG (w);
405     details = dialog->details;
406 
407     details->source = caja_file_get (source);
408     details->destination = caja_file_get (destination);
409     details->dest_dir = caja_file_get (dest_dir);
410 
411     build_dialog_appearance (dialog);
412 }
413 
414 static void
entry_text_changed_cb(GtkEditable * entry,CajaFileConflictDialog * dialog)415 entry_text_changed_cb (GtkEditable *entry,
416                        CajaFileConflictDialog *dialog)
417 {
418     CajaFileConflictDialogPrivate *details;
419 
420     details = dialog->details;
421 
422     /* The rename button is visible only if there's text
423      * in the entry.
424      */
425     if  (g_strcmp0 (gtk_entry_get_text (GTK_ENTRY (entry)), "") != 0 &&
426             g_strcmp0 (gtk_entry_get_text (GTK_ENTRY (entry)), details->conflict_name) != 0)
427     {
428         gtk_widget_hide (details->replace_button);
429         gtk_widget_show (details->rename_button);
430 
431         gtk_widget_set_sensitive (details->checkbox, FALSE);
432 
433         gtk_dialog_set_default_response (GTK_DIALOG (dialog),
434                                          CONFLICT_RESPONSE_RENAME);
435     }
436     else
437     {
438         gtk_widget_hide (details->rename_button);
439         gtk_widget_show (details->replace_button);
440 
441         gtk_widget_set_sensitive (details->checkbox, TRUE);
442 
443         gtk_dialog_set_default_response (GTK_DIALOG (dialog),
444                                          CONFLICT_RESPONSE_REPLACE);
445     }
446 }
447 
448 static void
expander_activated_cb(GtkExpander * w,CajaFileConflictDialog * dialog)449 expander_activated_cb (GtkExpander *w,
450                        CajaFileConflictDialog *dialog)
451 {
452     CajaFileConflictDialogPrivate *details;
453     int start_pos, end_pos;
454 
455     details = dialog->details;
456 
457     if (!gtk_expander_get_expanded (w))
458     {
459         if (g_strcmp0 (gtk_entry_get_text (GTK_ENTRY (details->entry)),
460                        details->conflict_name) == 0)
461         {
462             gtk_widget_grab_focus (details->entry);
463 
464             eel_filename_get_rename_region (details->conflict_name,
465                                             &start_pos, &end_pos);
466             gtk_editable_select_region (GTK_EDITABLE (details->entry),
467                                         start_pos, end_pos);
468         }
469     }
470 }
471 
472 static void
checkbox_toggled_cb(GtkToggleButton * t,CajaFileConflictDialog * dialog)473 checkbox_toggled_cb (GtkToggleButton *t,
474                      CajaFileConflictDialog *dialog)
475 {
476     CajaFileConflictDialogPrivate *details;
477 
478     details = dialog->details;
479 
480     gtk_widget_set_sensitive (details->expander,
481                               !gtk_toggle_button_get_active (t));
482     gtk_widget_set_sensitive (details->rename_button,
483                               !gtk_toggle_button_get_active (t));
484 
485     if  (!gtk_toggle_button_get_active (t) &&
486             g_strcmp0 (gtk_entry_get_text (GTK_ENTRY (details->entry)),
487                        "") != 0 &&
488             g_strcmp0 (gtk_entry_get_text (GTK_ENTRY (details->entry)),
489                        details->conflict_name) != 0)
490     {
491         gtk_widget_hide (details->replace_button);
492         gtk_widget_show (details->rename_button);
493     }
494     else
495     {
496         gtk_widget_hide (details->rename_button);
497         gtk_widget_show (details->replace_button);
498     }
499 }
500 
501 static void
reset_button_clicked_cb(GtkButton * w,CajaFileConflictDialog * dialog)502 reset_button_clicked_cb (GtkButton *w,
503                          CajaFileConflictDialog *dialog)
504 {
505     CajaFileConflictDialogPrivate *details;
506     int start_pos, end_pos;
507 
508     details = dialog->details;
509 
510     gtk_entry_set_text (GTK_ENTRY (details->entry),
511                         details->conflict_name);
512     gtk_widget_grab_focus (details->entry);
513     eel_filename_get_rename_region (details->conflict_name,
514                                     &start_pos, &end_pos);
515     gtk_editable_select_region (GTK_EDITABLE (details->entry),
516                                 start_pos, end_pos);
517 
518 }
519 
520 static void
diff_button_clicked_cb(GtkButton * w,CajaFileConflictDialog * dialog)521 diff_button_clicked_cb (GtkButton *w,
522                         CajaFileConflictDialog *dialog)
523 {
524     CajaFileConflictDialogPrivate *details;
525     details = dialog->details;
526 
527     GError *error;
528     char *command;
529 
530     command = g_find_program_in_path ("meld");
531     if (command)
532     {
533         char **argv;
534 
535         argv = g_new (char *, 4);
536         argv[0] = command;
537         argv[1] = g_file_get_path (caja_file_get_location (details->source));
538         argv[2] = g_file_get_path (caja_file_get_location (details->destination));
539         argv[3] = NULL;
540 
541         error = NULL;
542         if (!g_spawn_async_with_pipes (NULL,
543                                        argv,
544                                        NULL,
545                                        G_SPAWN_STDOUT_TO_DEV_NULL | G_SPAWN_STDERR_TO_DEV_NULL,
546                                        NULL,
547                                        NULL /* user_data */,
548                                        NULL,
549                                        NULL, NULL, NULL,
550                                        &error))
551         {
552             g_warning ("Error opening meld to show differences: %s\n", error->message);
553             g_error_free (error);
554         }
555         g_strfreev (argv);
556     }
557 }
558 
559 static void
caja_file_conflict_dialog_init(CajaFileConflictDialog * fcd)560 caja_file_conflict_dialog_init (CajaFileConflictDialog *fcd)
561 {
562     GtkWidget *hbox, *vbox, *vbox2;
563     GtkWidget *widget, *dialog_area;
564     CajaFileConflictDialogPrivate *details;
565     GtkDialog *dialog;
566 
567     details = fcd->details = caja_file_conflict_dialog_get_instance_private (fcd);
568     dialog = GTK_DIALOG (fcd);
569 
570     /* Setup the main hbox */
571     hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
572     dialog_area = gtk_dialog_get_content_area (dialog);
573     gtk_box_pack_start (GTK_BOX (dialog_area), hbox, FALSE, FALSE, 0);
574     gtk_container_set_border_width (GTK_CONTAINER (hbox), 6);
575 
576     /* Setup the dialog image */
577     widget = gtk_image_new_from_icon_name ("dialog-warning",
578                                        GTK_ICON_SIZE_DIALOG);
579     gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, FALSE, 0);
580     gtk_widget_set_halign (widget, GTK_ALIGN_CENTER);
581     gtk_widget_set_valign (widget, GTK_ALIGN_START);
582 
583     /* Setup the vbox containing the dialog body */
584     vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
585     gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0);
586 
587     /* Setup the vbox for the dialog labels */
588     widget = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
589     gtk_box_pack_start (GTK_BOX (vbox), widget, FALSE, FALSE, 0);
590     details->titles_vbox = widget;
591 
592     /* Setup the hboxes to pack file infos into */
593     vbox2 = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
594     gtk_widget_set_halign (vbox2, GTK_ALIGN_START);
595     gtk_widget_set_valign (vbox2, GTK_ALIGN_START);
596     gtk_widget_set_margin_start (vbox2, 12);
597     gtk_box_pack_start (GTK_BOX (vbox), vbox2, FALSE, FALSE, 0);
598 
599     hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
600     gtk_box_pack_start (GTK_BOX (vbox2), hbox, FALSE, FALSE, 0);
601     details->first_hbox = hbox;
602 
603     hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
604     gtk_box_pack_start (GTK_BOX (vbox2), hbox, FALSE, FALSE, 0);
605     details->second_hbox = hbox;
606 
607     /* Setup the expander for the rename action */
608     details->expander = gtk_expander_new_with_mnemonic (_("Select a new name for the _destination"));
609     gtk_box_pack_start (GTK_BOX (vbox2), details->expander, FALSE, FALSE, 0);
610     g_signal_connect (details->expander, "activate",
611                       G_CALLBACK (expander_activated_cb), dialog);
612 
613     hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
614     gtk_container_add (GTK_CONTAINER (details->expander), hbox);
615 
616     widget = gtk_entry_new ();
617     gtk_box_pack_start (GTK_BOX (hbox), widget, TRUE, TRUE, 6);
618     details->entry = widget;
619     g_signal_connect (widget, "changed",
620                       G_CALLBACK (entry_text_changed_cb), dialog);
621 
622     widget = gtk_button_new_with_label (_("Reset"));
623     gtk_button_set_image (GTK_BUTTON (widget),
624                           gtk_image_new_from_icon_name ("edit-undo",
625                                   GTK_ICON_SIZE_MENU));
626     gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, FALSE, 6);
627     g_signal_connect (widget, "clicked",
628                       G_CALLBACK (reset_button_clicked_cb), dialog);
629 
630     gtk_widget_show_all (vbox2);
631 
632     /* Setup the diff button for text files */
633     details->diff_button = gtk_button_new_with_label (_("Differences..."));
634     gtk_button_set_image (GTK_BUTTON (details->diff_button),
635                           gtk_image_new_from_icon_name ("edit-find",
636                                   GTK_ICON_SIZE_MENU));
637     gtk_box_pack_start (GTK_BOX (vbox), details->diff_button, FALSE, FALSE, 6);
638     g_signal_connect (details->diff_button, "clicked",
639                       G_CALLBACK (diff_button_clicked_cb), dialog);
640     gtk_widget_hide (details->diff_button);
641 
642     /* Setup the checkbox to apply the action to all files */
643     widget = gtk_check_button_new_with_mnemonic (_("Apply this action to all files and folders"));
644 
645     gtk_box_pack_start (GTK_BOX (vbox),
646                         widget, FALSE, FALSE, 0);
647     details->checkbox = widget;
648     g_signal_connect (widget, "toggled",
649                       G_CALLBACK (checkbox_toggled_cb), dialog);
650 
651     /* Add buttons */
652     eel_dialog_add_button (dialog,
653                            _("_Cancel"),
654                            "process-stop",
655                            GTK_RESPONSE_CANCEL);
656 
657     gtk_dialog_add_button (dialog,
658                            _("_Skip"),
659                            CONFLICT_RESPONSE_SKIP);
660 
661     details->rename_button =
662         gtk_dialog_add_button (dialog,
663                                _("Re_name"),
664                                CONFLICT_RESPONSE_RENAME);
665     gtk_widget_hide (details->rename_button);
666 
667     details->replace_button =
668         gtk_dialog_add_button (dialog,
669                                _("Replace"),
670                                CONFLICT_RESPONSE_REPLACE);
671     gtk_widget_grab_focus (details->replace_button);
672 
673     /* Setup HIG properties */
674     gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
675     gtk_box_set_spacing (GTK_BOX (gtk_dialog_get_content_area (dialog)), 14);
676     gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
677 
678     gtk_widget_show_all (dialog_area);
679 }
680 
681 static void
do_finalize(GObject * self)682 do_finalize (GObject *self)
683 {
684     CajaFileConflictDialogPrivate *details =
685         CAJA_FILE_CONFLICT_DIALOG (self)->details;
686 
687     g_free (details->conflict_name);
688 
689     if (details->handle != NULL)
690     {
691         caja_file_list_cancel_call_when_ready (details->handle);
692     }
693 
694     if (details->src_handler_id)
695     {
696         g_signal_handler_disconnect (details->source, details->src_handler_id);
697         caja_file_monitor_remove (details->source, self);
698     }
699 
700     if (details->dest_handler_id)
701     {
702         g_signal_handler_disconnect (details->destination, details->dest_handler_id);
703         caja_file_monitor_remove (details->destination, self);
704     }
705 
706     caja_file_unref (details->source);
707     caja_file_unref (details->destination);
708     caja_file_unref (details->dest_dir);
709 
710     G_OBJECT_CLASS (caja_file_conflict_dialog_parent_class)->finalize (self);
711 }
712 
713 static void
caja_file_conflict_dialog_class_init(CajaFileConflictDialogClass * klass)714 caja_file_conflict_dialog_class_init (CajaFileConflictDialogClass *klass)
715 {
716     G_OBJECT_CLASS (klass)->finalize = do_finalize;
717 }
718 
719 char *
caja_file_conflict_dialog_get_new_name(CajaFileConflictDialog * dialog)720 caja_file_conflict_dialog_get_new_name (CajaFileConflictDialog *dialog)
721 {
722     return g_strdup (gtk_entry_get_text
723                      (GTK_ENTRY (dialog->details->entry)));
724 }
725 
726 gboolean
caja_file_conflict_dialog_get_apply_to_all(CajaFileConflictDialog * dialog)727 caja_file_conflict_dialog_get_apply_to_all (CajaFileConflictDialog *dialog)
728 {
729     return gtk_toggle_button_get_active
730            (GTK_TOGGLE_BUTTON (dialog->details->checkbox));
731 }
732 
733 GtkWidget *
caja_file_conflict_dialog_new(GtkWindow * parent,GFile * source,GFile * destination,GFile * dest_dir)734 caja_file_conflict_dialog_new (GtkWindow *parent,
735                                GFile *source,
736                                GFile *destination,
737                                GFile *dest_dir)
738 {
739     GtkWidget *dialog;
740     CajaFile *src, *dest;
741     gboolean source_is_dir, dest_is_dir;
742 
743     src = caja_file_get (source);
744     dest = caja_file_get (destination);
745 
746     source_is_dir = caja_file_is_directory (src);
747     dest_is_dir = caja_file_is_directory (dest);
748 
749     if (source_is_dir) {
750         dialog = GTK_WIDGET (g_object_new (CAJA_TYPE_FILE_CONFLICT_DIALOG,
751                                            "title", dest_is_dir ? _("Merge Folder") : _("File and Folder conflict"),
752                                            NULL));
753     }
754     else {
755         dialog = GTK_WIDGET (g_object_new (CAJA_TYPE_FILE_CONFLICT_DIALOG,
756                                            "title", dest_is_dir ? _("File and Folder conflict") : _("File conflict"),
757                                            NULL));
758     }
759 
760     set_source_and_destination (dialog,
761                                 source,
762                                 destination,
763                                 dest_dir);
764     gtk_window_set_transient_for (GTK_WINDOW (dialog),
765                                   parent);
766     return dialog;
767 }
768