No issues found
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2
3 /* nautilus-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., 59 Temple Place - Suite 330,
21 Boston, MA 02111-1307, USA.
22
23 Authors: Cosimo Cecchi <cosimoc@gnome.org>
24 */
25
26 #include <config.h>
27 #include "nautilus-file-conflict-dialog.h"
28
29 #include <string.h>
30 #include <glib-object.h>
31 #include <gio/gio.h>
32 #include <glib/gi18n.h>
33 #include <pango/pango.h>
34 #include <eel/eel-vfs-extensions.h>
35
36 #include "nautilus-file.h"
37 #include "nautilus-icon-info.h"
38
39 struct _NautilusFileConflictDialogDetails
40 {
41 /* conflicting objects */
42 NautilusFile *source;
43 NautilusFile *destination;
44 NautilusFile *dest_dir;
45
46 gchar *conflict_name;
47 NautilusFileListHandle *handle;
48 gulong src_handler_id;
49 gulong dest_handler_id;
50
51 /* UI objects */
52 GtkWidget *titles_vbox;
53 GtkWidget *first_hbox;
54 GtkWidget *second_hbox;
55 GtkWidget *expander;
56 GtkWidget *entry;
57 GtkWidget *checkbox;
58 GtkWidget *rename_button;
59 GtkWidget *replace_button;
60 GtkWidget *dest_image;
61 GtkWidget *src_image;
62 };
63
64 G_DEFINE_TYPE (NautilusFileConflictDialog,
65 nautilus_file_conflict_dialog,
66 GTK_TYPE_DIALOG);
67
68 #define NAUTILUS_FILE_CONFLICT_DIALOG_GET_PRIVATE(object) \
69 (G_TYPE_INSTANCE_GET_PRIVATE ((object), NAUTILUS_TYPE_FILE_CONFLICT_DIALOG, \
70 NautilusFileConflictDialogDetails))
71
72 static void
73 file_icons_changed (NautilusFile *file,
74 NautilusFileConflictDialog *fcd)
75 {
76 GdkPixbuf *pixbuf;
77
78 pixbuf = nautilus_file_get_icon_pixbuf (fcd->details->destination,
79 NAUTILUS_ICON_SIZE_LARGE,
80 TRUE,
81 NAUTILUS_FILE_ICON_FLAGS_USE_THUMBNAILS);
82
83 gtk_image_set_from_pixbuf (GTK_IMAGE (fcd->details->dest_image), pixbuf);
84 g_object_unref (pixbuf);
85
86 pixbuf = nautilus_file_get_icon_pixbuf (fcd->details->source,
87 NAUTILUS_ICON_SIZE_LARGE,
88 TRUE,
89 NAUTILUS_FILE_ICON_FLAGS_USE_THUMBNAILS);
90
91 gtk_image_set_from_pixbuf (GTK_IMAGE (fcd->details->src_image), pixbuf);
92 g_object_unref (pixbuf);
93 }
94
95 static void
96 file_list_ready_cb (GList *files,
97 gpointer user_data)
98 {
99 NautilusFileConflictDialog *fcd = user_data;
100 NautilusFile *src, *dest, *dest_dir;
101 time_t src_mtime, dest_mtime;
102 gboolean source_is_dir, dest_is_dir, should_show_type;
103 NautilusFileConflictDialogDetails *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 GdkPixbuf *pixbuf;
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 = nautilus_file_get_mtime (src);
123 dest_mtime = nautilus_file_get_mtime (dest);
124
125 dest_name = nautilus_file_get_display_name (dest);
126 dest_dir_name = nautilus_file_get_display_name (dest_dir);
127
128 source_is_dir = nautilus_file_is_directory (src);
129 dest_is_dir = nautilus_file_is_directory (dest);
130
131 type = nautilus_file_get_mime_type (dest);
132 should_show_type = !nautilus_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 if (source_is_dir) {
140 primary_text = g_strdup_printf
141 (_("Merge folder “%s”?"),
142 dest_name);
143
144 message_extra =
145 _("Merging will ask for confirmation before replacing any files in "
146 "the folder that conflict with the files being copied.");
147
148 if (src_mtime > dest_mtime) {
149 message = g_strdup_printf (
150 _("An older folder with the same name already exists in “%s”."),
151 dest_dir_name);
152 } else if (src_mtime < dest_mtime) {
153 message = g_strdup_printf (
154 _("A newer folder with the same name already exists in “%s”."),
155 dest_dir_name);
156 } else {
157 message = g_strdup_printf (
158 _("Another folder with the same name already exists in “%s”."),
159 dest_dir_name);
160 }
161 } else {
162 message_extra =
163 _("Replacing it will remove all files in the folder.");
164 primary_text = g_strdup_printf
165 (_("Replace folder “%s”?"), dest_name);
166 message = g_strdup_printf
167 (_("A folder with the same name already exists in “%s”."),
168 dest_dir_name);
169 }
170 } else {
171 primary_text = g_strdup_printf
172 (_("Replace file “%s”?"), dest_name);
173
174 message_extra = _("Replacing it will overwrite its content.");
175
176 if (src_mtime > dest_mtime) {
177 message = g_strdup_printf (
178 _("An older file with the same name already exists in “%s”."),
179 dest_dir_name);
180 } else if (src_mtime < dest_mtime) {
181 message = g_strdup_printf (
182 _("A newer file with the same name already exists in “%s”."),
183 dest_dir_name);
184 } else {
185 message = g_strdup_printf (
186 _("Another file with the same name already exists in “%s”."),
187 dest_dir_name);
188 }
189 }
190
191 secondary_text = g_strdup_printf ("%s\n%s", message, message_extra);
192 g_free (message);
193
194 label = gtk_label_new (primary_text);
195 gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
196 gtk_label_set_line_wrap_mode (GTK_LABEL (label), PANGO_WRAP_WORD_CHAR);
197 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
198 gtk_box_pack_start (GTK_BOX (details->titles_vbox),
199 label, FALSE, FALSE, 0);
200 gtk_widget_show (label);
201
202 attr_list = pango_attr_list_new ();
203 pango_attr_list_insert (attr_list, pango_attr_weight_new (PANGO_WEIGHT_BOLD));
204 pango_attr_list_insert (attr_list, pango_attr_scale_new (PANGO_SCALE_LARGE));
205 g_object_set (label,
206 "attributes", attr_list,
207 NULL);
208
209 pango_attr_list_unref (attr_list);
210
211 label = gtk_label_new (secondary_text);
212 gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
213 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
214 gtk_box_pack_start (GTK_BOX (details->titles_vbox),
215 label, FALSE, FALSE, 0);
216 gtk_widget_show (label);
217 g_free (primary_text);
218 g_free (secondary_text);
219
220 /* Set up file icons */
221 pixbuf = nautilus_file_get_icon_pixbuf (dest,
222 NAUTILUS_ICON_SIZE_LARGE,
223 TRUE,
224 NAUTILUS_FILE_ICON_FLAGS_USE_THUMBNAILS);
225 details->dest_image = gtk_image_new_from_pixbuf (pixbuf);
226 gtk_box_pack_start (GTK_BOX (details->first_hbox),
227 details->dest_image, FALSE, FALSE, 0);
228 gtk_widget_show (details->dest_image);
229 g_object_unref (pixbuf);
230
231 pixbuf = nautilus_file_get_icon_pixbuf (src,
232 NAUTILUS_ICON_SIZE_LARGE,
233 TRUE,
234 NAUTILUS_FILE_ICON_FLAGS_USE_THUMBNAILS);
235 details->src_image = gtk_image_new_from_pixbuf (pixbuf);
236 gtk_box_pack_start (GTK_BOX (details->second_hbox),
237 details->src_image, FALSE, FALSE, 0);
238 gtk_widget_show (details->src_image);
239 g_object_unref (pixbuf);
240
241 /* Set up labels */
242 label = gtk_label_new (NULL);
243 date = nautilus_file_get_string_attribute (dest,
244 "date_modified");
245 size = nautilus_file_get_string_attribute (dest, "size");
246
247 if (should_show_type) {
248 type = nautilus_file_get_string_attribute (dest, "type");
249 }
250
251 str = g_string_new (NULL);
252 g_string_append_printf (str, "<b>%s</b>\n", _("Original file"));
253 g_string_append_printf (str, "%s %s\n", _("Size:"), size);
254
255 if (should_show_type) {
256 g_string_append_printf (str, "%s %s\n", _("Type:"), type);
257 }
258
259 g_string_append_printf (str, "%s %s", _("Last modified:"), date);
260
261 label_text = str->str;
262 gtk_label_set_markup (GTK_LABEL (label),
263 label_text);
264 gtk_box_pack_start (GTK_BOX (details->first_hbox),
265 label, FALSE, FALSE, 0);
266 gtk_widget_show (label);
267
268 g_free (size);
269 g_free (type);
270 g_free (date);
271 g_string_erase (str, 0, -1);
272
273 /* Second label */
274 label = gtk_label_new (NULL);
275 date = nautilus_file_get_string_attribute (src,
276 "date_modified");
277 size = nautilus_file_get_string_attribute (src, "size");
278
279 if (should_show_type) {
280 type = nautilus_file_get_string_attribute (src, "type");
281 }
282
283 g_string_append_printf (str, "<b>%s</b>\n", _("Replace with"));
284 g_string_append_printf (str, "%s %s\n", _("Size:"), size);
285
286 if (should_show_type) {
287 g_string_append_printf (str, "%s %s\n", _("Type:"), type);
288 }
289
290 g_string_append_printf (str, "%s %s", _("Last modified:"), date);
291 label_text = g_string_free (str, FALSE);
292
293 gtk_label_set_markup (GTK_LABEL (label),
294 label_text);
295 gtk_box_pack_start (GTK_BOX (details->second_hbox),
296 label, FALSE, FALSE, 0);
297 gtk_widget_show (label);
298
299 g_free (size);
300 g_free (date);
301 g_free (type);
302 g_free (label_text);
303
304 /* Populate the entry */
305 edit_name = nautilus_file_get_edit_name (dest);
306 details->conflict_name = edit_name;
307
308 gtk_entry_set_text (GTK_ENTRY (details->entry), edit_name);
309
310 if (source_is_dir && dest_is_dir) {
311 gtk_button_set_label (GTK_BUTTON (details->replace_button),
312 _("Merge"));
313 }
314
315 nautilus_file_monitor_add (src, fcd, NAUTILUS_FILE_ATTRIBUTES_FOR_ICON);
316 nautilus_file_monitor_add (dest, fcd, NAUTILUS_FILE_ATTRIBUTES_FOR_ICON);
317
318 details->src_handler_id = g_signal_connect (src, "changed",
319 G_CALLBACK (file_icons_changed), fcd);
320 details->dest_handler_id = g_signal_connect (dest, "changed",
321 G_CALLBACK (file_icons_changed), fcd);
322 }
323
324 static void
325 build_dialog_appearance (NautilusFileConflictDialog *fcd)
326 {
327 GList *files = NULL;
328 NautilusFileConflictDialogDetails *details = fcd->details;
329
330 files = g_list_prepend (files, details->source);
331 files = g_list_prepend (files, details->destination);
332 files = g_list_prepend (files, details->dest_dir);
333
334 nautilus_file_list_call_when_ready (files,
335 NAUTILUS_FILE_ATTRIBUTES_FOR_ICON,
336 &details->handle, file_list_ready_cb, fcd);
337 g_list_free (files);
338 }
339
340 static void
341 set_source_and_destination (GtkWidget *w,
342 GFile *source,
343 GFile *destination,
344 GFile *dest_dir)
345 {
346 NautilusFileConflictDialog *dialog;
347 NautilusFileConflictDialogDetails *details;
348
349 dialog = NAUTILUS_FILE_CONFLICT_DIALOG (w);
350 details = dialog->details;
351
352 details->source = nautilus_file_get (source);
353 details->destination = nautilus_file_get (destination);
354 details->dest_dir = nautilus_file_get (dest_dir);
355
356 build_dialog_appearance (dialog);
357 }
358
359 static void
360 entry_text_changed_cb (GtkEditable *entry,
361 NautilusFileConflictDialog *dialog)
362 {
363 NautilusFileConflictDialogDetails *details;
364
365 details = dialog->details;
366
367 /* The rename button is visible only if there's text
368 * in the entry.
369 */
370 if (g_strcmp0 (gtk_entry_get_text (GTK_ENTRY (entry)), "") != 0 &&
371 g_strcmp0 (gtk_entry_get_text (GTK_ENTRY (entry)), details->conflict_name) != 0) {
372 gtk_widget_hide (details->replace_button);
373 gtk_widget_show (details->rename_button);
374
375 gtk_widget_set_sensitive (details->checkbox, FALSE);
376
377 gtk_dialog_set_default_response (GTK_DIALOG (dialog),
378 CONFLICT_RESPONSE_RENAME);
379 } else {
380 gtk_widget_hide (details->rename_button);
381 gtk_widget_show (details->replace_button);
382
383 gtk_widget_set_sensitive (details->checkbox, TRUE);
384
385 gtk_dialog_set_default_response (GTK_DIALOG (dialog),
386 CONFLICT_RESPONSE_REPLACE);
387 }
388 }
389
390 static void
391 expander_activated_cb (GtkExpander *w,
392 NautilusFileConflictDialog *dialog)
393 {
394 NautilusFileConflictDialogDetails *details;
395 int start_pos, end_pos;
396
397 details = dialog->details;
398
399 if (!gtk_expander_get_expanded (w)) {
400 if (g_strcmp0 (gtk_entry_get_text (GTK_ENTRY (details->entry)),
401 details->conflict_name) == 0) {
402 gtk_widget_grab_focus (details->entry);
403
404 eel_filename_get_rename_region (details->conflict_name,
405 &start_pos, &end_pos);
406 gtk_editable_select_region (GTK_EDITABLE (details->entry),
407 start_pos, end_pos);
408 }
409 }
410 }
411
412 static void
413 checkbox_toggled_cb (GtkToggleButton *t,
414 NautilusFileConflictDialog *dialog)
415 {
416 NautilusFileConflictDialogDetails *details;
417
418 details = dialog->details;
419
420 gtk_widget_set_sensitive (details->expander,
421 !gtk_toggle_button_get_active (t));
422 gtk_widget_set_sensitive (details->rename_button,
423 !gtk_toggle_button_get_active (t));
424
425 if (!gtk_toggle_button_get_active (t) &&
426 g_strcmp0 (gtk_entry_get_text (GTK_ENTRY (details->entry)),
427 "") != 0 &&
428 g_strcmp0 (gtk_entry_get_text (GTK_ENTRY (details->entry)),
429 details->conflict_name) != 0) {
430 gtk_widget_hide (details->replace_button);
431 gtk_widget_show (details->rename_button);
432 } else {
433 gtk_widget_hide (details->rename_button);
434 gtk_widget_show (details->replace_button);
435 }
436 }
437
438 static void
439 reset_button_clicked_cb (GtkButton *w,
440 NautilusFileConflictDialog *dialog)
441 {
442 NautilusFileConflictDialogDetails *details;
443 int start_pos, end_pos;
444
445 details = dialog->details;
446
447 gtk_entry_set_text (GTK_ENTRY (details->entry),
448 details->conflict_name);
449 gtk_widget_grab_focus (details->entry);
450 eel_filename_get_rename_region (details->conflict_name,
451 &start_pos, &end_pos);
452 gtk_editable_select_region (GTK_EDITABLE (details->entry),
453 start_pos, end_pos);
454
455 }
456
457 static void
458 nautilus_file_conflict_dialog_init (NautilusFileConflictDialog *fcd)
459 {
460 GtkWidget *hbox, *vbox, *vbox2, *alignment;
461 GtkWidget *widget, *dialog_area;
462 NautilusFileConflictDialogDetails *details;
463 GtkDialog *dialog;
464
465 details = fcd->details = NAUTILUS_FILE_CONFLICT_DIALOG_GET_PRIVATE (fcd);
466 dialog = GTK_DIALOG (fcd);
467
468 /* Setup the main hbox */
469 hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
470 dialog_area = gtk_dialog_get_content_area (dialog);
471 gtk_box_pack_start (GTK_BOX (dialog_area), hbox, FALSE, FALSE, 0);
472 gtk_container_set_border_width (GTK_CONTAINER (hbox), 6);
473
474 /* Setup the dialog image */
475 widget = gtk_image_new_from_stock (GTK_STOCK_DIALOG_WARNING,
476 GTK_ICON_SIZE_DIALOG);
477 gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, FALSE, 0);
478 gtk_misc_set_alignment (GTK_MISC (widget), 0.5, 0.0);
479
480 /* Setup the vbox containing the dialog body */
481 vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
482 gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0);
483
484 /* Setup the vbox for the dialog labels */
485 widget = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
486 gtk_box_pack_start (GTK_BOX (vbox), widget, FALSE, FALSE, 0);
487 details->titles_vbox = widget;
488
489 /* Setup the hboxes to pack file infos into */
490 alignment = gtk_alignment_new (0.0, 0.0, 0.0, 0.0);
491 g_object_set (alignment, "left-padding", 12, NULL);
492 vbox2 = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
493 gtk_container_add (GTK_CONTAINER (alignment), vbox2);
494 gtk_box_pack_start (GTK_BOX (vbox), alignment, FALSE, FALSE, 0);
495
496 hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
497 gtk_box_pack_start (GTK_BOX (vbox2), hbox, FALSE, FALSE, 0);
498 details->first_hbox = hbox;
499
500 hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
501 gtk_box_pack_start (GTK_BOX (vbox2), hbox, FALSE, FALSE, 0);
502 details->second_hbox = hbox;
503
504 /* Setup the expander for the rename action */
505 details->expander = gtk_expander_new_with_mnemonic (_("_Select a new name for the destination"));
506 gtk_box_pack_start (GTK_BOX (vbox2), details->expander, FALSE, FALSE, 0);
507 g_signal_connect (details->expander, "activate",
508 G_CALLBACK (expander_activated_cb), dialog);
509
510 hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
511 gtk_container_add (GTK_CONTAINER (details->expander), hbox);
512
513 widget = gtk_entry_new ();
514 gtk_box_pack_start (GTK_BOX (hbox), widget, TRUE, TRUE, 6);
515 details->entry = widget;
516 g_signal_connect (widget, "changed",
517 G_CALLBACK (entry_text_changed_cb), dialog);
518
519 widget = gtk_button_new_with_label (_("Reset"));
520 gtk_button_set_image (GTK_BUTTON (widget),
521 gtk_image_new_from_stock (GTK_STOCK_UNDO,
522 GTK_ICON_SIZE_MENU));
523 gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, FALSE, 6);
524 g_signal_connect (widget, "clicked",
525 G_CALLBACK (reset_button_clicked_cb), dialog);
526
527 gtk_widget_show_all (alignment);
528
529
530 /* Setup the checkbox to apply the action to all files */
531 widget = gtk_check_button_new_with_mnemonic (_("Apply this action to all files"));
532 gtk_box_pack_start (GTK_BOX (vbox),
533 widget, FALSE, FALSE, 0);
534 details->checkbox = widget;
535 g_signal_connect (widget, "toggled",
536 G_CALLBACK (checkbox_toggled_cb), dialog);
537
538 /* Add buttons */
539 gtk_dialog_add_buttons (dialog,
540 GTK_STOCK_CANCEL,
541 GTK_RESPONSE_CANCEL,
542 _("_Skip"),
543 CONFLICT_RESPONSE_SKIP,
544 NULL);
545 details->rename_button =
546 gtk_dialog_add_button (dialog,
547 _("Re_name"),
548 CONFLICT_RESPONSE_RENAME);
549 gtk_widget_hide (details->rename_button);
550
551 details->replace_button =
552 gtk_dialog_add_button (dialog,
553 _("Replace"),
554 CONFLICT_RESPONSE_REPLACE);
555 gtk_widget_grab_focus (details->replace_button);
556
557 /* Setup HIG properties */
558 gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
559 gtk_box_set_spacing (GTK_BOX (gtk_dialog_get_content_area (dialog)), 14);
560 gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
561
562 gtk_widget_show_all (dialog_area);
563 }
564
565 static void
566 do_finalize (GObject *self)
567 {
568 NautilusFileConflictDialogDetails *details =
569 NAUTILUS_FILE_CONFLICT_DIALOG (self)->details;
570
571 g_free (details->conflict_name);
572
573 if (details->handle != NULL) {
574 nautilus_file_list_cancel_call_when_ready (details->handle);
575 }
576
577 if (details->src_handler_id) {
578 g_signal_handler_disconnect (details->source, details->src_handler_id);
579 nautilus_file_monitor_remove (details->source, self);
580 }
581
582 if (details->dest_handler_id) {
583 g_signal_handler_disconnect (details->destination, details->dest_handler_id);
584 nautilus_file_monitor_remove (details->destination, self);
585 }
586
587 nautilus_file_unref (details->source);
588 nautilus_file_unref (details->destination);
589 nautilus_file_unref (details->dest_dir);
590
591 G_OBJECT_CLASS (nautilus_file_conflict_dialog_parent_class)->finalize (self);
592 }
593
594 static void
595 nautilus_file_conflict_dialog_class_init (NautilusFileConflictDialogClass *klass)
596 {
597 G_OBJECT_CLASS (klass)->finalize = do_finalize;
598
599 g_type_class_add_private (klass, sizeof (NautilusFileConflictDialogDetails));
600 }
601
602 char *
603 nautilus_file_conflict_dialog_get_new_name (NautilusFileConflictDialog *dialog)
604 {
605 return g_strdup (gtk_entry_get_text
606 (GTK_ENTRY (dialog->details->entry)));
607 }
608
609 gboolean
610 nautilus_file_conflict_dialog_get_apply_to_all (NautilusFileConflictDialog *dialog)
611 {
612 return gtk_toggle_button_get_active
613 (GTK_TOGGLE_BUTTON (dialog->details->checkbox));
614 }
615
616 GtkWidget *
617 nautilus_file_conflict_dialog_new (GtkWindow *parent,
618 GFile *source,
619 GFile *destination,
620 GFile *dest_dir)
621 {
622 GtkWidget *dialog;
623
624 dialog = GTK_WIDGET (g_object_new (NAUTILUS_TYPE_FILE_CONFLICT_DIALOG,
625 "title", _("File conflict"),
626 NULL));
627 set_source_and_destination (dialog,
628 source,
629 destination,
630 dest_dir);
631 gtk_window_set_transient_for (GTK_WINDOW (dialog),
632 parent);
633 return dialog;
634 }