Fri Oct 13 05:22:43 2006 John Ellis <johne@verizon.net>
[geeqie.git] / src / utilops.c
1 /*
2  * GQview
3  * (C) 2006 John Ellis
4  *
5  * Author: John Ellis
6  *
7  * This software is released under the GNU General Public License (GNU GPL).
8  * Please read the included file COPYING for more information.
9  * This software comes with no warranty of any kind, use at your own risk!
10  */
11
12
13 #include "gqview.h"
14 #include "utilops.h"
15
16
17 #include "cache_maint.h"
18 #include "collect.h"
19 #include "dupe.h"
20 #include "filelist.h"
21 #include "image.h"
22 #include "img-view.h"
23 #include "layout.h"
24 #include "search.h"
25 #include "ui_bookmark.h"
26 #include "ui_fileops.h"
27 #include "ui_misc.h"
28 #include "ui_tabcomp.h"
29
30
31 /*
32  *--------------------------------------------------------------------------
33  * call these when names change, files move, deleted, etc.
34  * so that any open windows are also updated
35  *--------------------------------------------------------------------------
36  */
37
38 void file_maint_renamed(const gchar *source, const gchar *dest)
39 {
40         cache_maint_moved(source, dest);
41         collection_maint_renamed(source, dest);
42
43         layout_maint_renamed(source, dest);
44         view_window_maint_moved(source, dest);
45         dupe_maint_renamed(source, dest);
46         search_maint_renamed(source, dest);
47 }
48
49 /* under most cases ignore_list should be NULL */
50 void file_maint_removed(const gchar *path, GList *ignore_list)
51 {
52         layout_maint_removed(path, ignore_list);
53         view_window_maint_removed(path, ignore_list);
54         dupe_maint_removed(path);
55         search_maint_removed(path);
56
57         collection_maint_removed(path);
58         cache_maint_removed(path);
59 }
60
61 /* special case for correct main window behavior */
62 void file_maint_moved(const gchar *source, const gchar *dest, GList *ignore_list)
63 {
64         cache_maint_moved(source, dest);
65         collection_maint_renamed(source, dest);
66
67         layout_maint_moved(source, dest, ignore_list);
68         view_window_maint_moved(source, dest);
69         dupe_maint_renamed(source, dest);
70         search_maint_renamed(source, dest);
71 }
72
73 void file_maint_copied(const gchar *source, const gchar *dest)
74 {
75         cache_maint_copied(source, dest);
76 }
77
78 /*
79  *--------------------------------------------------------------------------
80  * The file manipulation dialogs
81  *--------------------------------------------------------------------------
82  */
83
84
85 enum {
86         DIALOG_NEW_DIR,
87         DIALOG_COPY,
88         DIALOG_MOVE,
89         DIALOG_DELETE,
90         DIALOG_RENAME
91 };
92
93 typedef struct _FileDataMult FileDataMult;
94 struct _FileDataMult
95 {
96         gint confirm_all;
97         gint confirmed;
98         gint skip;
99         GList *source_list;
100         GList *source_next;
101         gchar *dest_base;
102         gchar *source;
103         gchar *dest;
104         gint copy;
105
106         gint rename;
107         gint rename_auto;
108         gint rename_all;
109
110         GtkWidget *rename_box;
111         GtkWidget *rename_entry;
112         GtkWidget *rename_auto_box;
113
114         GtkWidget *yes_all_button;
115 };
116
117 typedef struct _FileDataSingle FileDataSingle;
118 struct _FileDataSingle
119 {
120         gint confirmed;
121         gchar *source;
122         gchar *dest;
123         gint copy;
124
125         gint rename;
126         gint rename_auto;
127
128         GtkWidget *rename_box;
129         GtkWidget *rename_entry;
130         GtkWidget *rename_auto_box;
131 };
132
133 /*
134  *--------------------------------------------------------------------------
135  * Adds 1 or 2 images (if 2, side by side) to a GenericDialog
136  *--------------------------------------------------------------------------
137  */
138
139 #define DIALOG_DEF_IMAGE_DIM_X 200
140 #define DIALOG_DEF_IMAGE_DIM_Y 150
141
142 static void generic_dialog_add_image(GenericDialog *gd, const gchar *path1, const gchar *header1,
143                                      const gchar *path2, const gchar *header2,
144                                      gint show_filename)
145 {
146         ImageWindow *imd;
147         GtkWidget *hbox = NULL;
148         GtkWidget *vbox;
149         GtkWidget *label = NULL;
150
151         if (path2)
152                 {
153                 hbox = pref_box_new(gd->vbox, TRUE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
154                 }
155
156         /* image 1 */
157
158         vbox = gtk_vbox_new(FALSE, PREF_PAD_GAP);
159         if (hbox)
160                 {
161                 GtkWidget *sep;
162
163                 gtk_box_pack_start(GTK_BOX(hbox), vbox, TRUE, TRUE, 0);
164
165                 sep = gtk_vseparator_new();
166                 gtk_box_pack_start(GTK_BOX(hbox), sep, FALSE, FALSE, 0);
167                 gtk_widget_show(sep);
168                 }
169         else
170                 {
171                 gtk_box_pack_start(GTK_BOX(gd->vbox), vbox, TRUE, TRUE, PREF_PAD_GAP);
172                 }
173         gtk_widget_show(vbox);
174
175         if (header1)
176                 {
177                 GtkWidget *head;
178
179                 head = pref_label_new(vbox, header1);
180                 pref_label_bold(head, TRUE, FALSE);
181                 gtk_misc_set_alignment(GTK_MISC(head), 0.0, 0.5);
182                 }
183
184         imd = image_new(FALSE);
185         gtk_widget_set_size_request(imd->widget, DIALOG_DEF_IMAGE_DIM_X, DIALOG_DEF_IMAGE_DIM_Y);
186         gtk_box_pack_start(GTK_BOX(vbox), imd->widget, TRUE, TRUE, 0);
187         image_change_path(imd, path1, 0.0);
188         gtk_widget_show(imd->widget);
189
190         if (show_filename)
191                 {
192                 label = pref_label_new(vbox, (path1 == NULL) ? "" : filename_from_path(path1));
193                 }
194
195         /* only the first image is stored (for use in gd_image_set) */
196         g_object_set_data(G_OBJECT(gd->dialog), "img_image", imd);
197         g_object_set_data(G_OBJECT(gd->dialog), "img_label", label);
198                 
199
200         /* image 2 */
201
202         if (hbox && path2)
203                 {
204                 vbox = pref_box_new(hbox, TRUE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
205
206                 if (header2)
207                         {
208                         GtkWidget *head;
209
210                         head = pref_label_new(vbox, header2);
211                         pref_label_bold(head, TRUE, FALSE);
212                         gtk_misc_set_alignment(GTK_MISC(head), 0.0, 0.5);
213                         }
214
215                 imd = image_new(FALSE);
216                 gtk_widget_set_size_request(imd->widget, DIALOG_DEF_IMAGE_DIM_X, DIALOG_DEF_IMAGE_DIM_Y);
217                 gtk_box_pack_start(GTK_BOX(vbox), imd->widget, TRUE, TRUE, 0);
218                 image_change_path(imd, path2, 0.0);
219                 gtk_widget_show(imd->widget);
220
221                 pref_label_new(vbox, filename_from_path(path2));
222                 }
223 }
224
225 static void generic_dialog_image_set(GenericDialog *gd, const gchar *path)
226 {
227         ImageWindow *imd;
228         GtkWidget *label;
229         
230         imd = g_object_get_data(G_OBJECT(gd->dialog), "img_image");
231         label = g_object_get_data(G_OBJECT(gd->dialog), "img_label");
232
233         if (!imd) return;
234
235         image_change_path(imd, path, 0.0);
236         if (label) gtk_label_set_text(GTK_LABEL(label), filename_from_path(path));
237 }
238
239 /*
240  *--------------------------------------------------------------------------
241  * Wrappers to aid in setting additional dialog properties (unde mouse, etc.)
242  *--------------------------------------------------------------------------
243  */
244
245 GenericDialog *file_util_gen_dlg(const gchar *title,
246                                  const gchar *wmclass, const gchar *wmsubclass,
247                                  GtkWidget *parent, gint auto_close,
248                                  void (*cancel_cb)(GenericDialog *, gpointer), gpointer data)
249 {
250         GenericDialog *gd;
251
252         gd = generic_dialog_new(title, wmclass, wmsubclass, parent, auto_close, cancel_cb, data);
253         if (place_dialogs_under_mouse)
254                 {
255                 gtk_window_set_position(GTK_WINDOW(gd->dialog), GTK_WIN_POS_MOUSE);
256                 }
257
258         return gd;
259 }
260
261 FileDialog *file_util_file_dlg(const gchar *title,
262                                const gchar *wmclass, const gchar *wmsubclass,
263                                GtkWidget *parent,
264                                void (*cancel_cb)(FileDialog *, gpointer), gpointer data)
265 {
266         FileDialog *fd;
267
268         fd = file_dialog_new(title, wmclass, wmsubclass, parent, cancel_cb, data);
269         if (place_dialogs_under_mouse)
270                 {
271                 gtk_window_set_position(GTK_WINDOW(GENERIC_DIALOG(fd)->dialog), GTK_WIN_POS_MOUSE);
272                 }
273
274         return fd;
275 }
276
277 /* this warning dialog is copied from SLIK's ui_utildg.c,
278  * because it does not have a mouse center option,
279  * and we must center it before show, implement it here.
280  */
281 static void file_util_warning_dialog_ok_cb(GenericDialog *gd, gpointer data)
282 {
283         /* no op */
284 }
285
286 GenericDialog *file_util_warning_dialog(const gchar *heading, const gchar *message,
287                                         const gchar *icon_stock_id, GtkWidget *parent)
288 {
289         GenericDialog *gd;
290
291         gd = file_util_gen_dlg(heading, "GQview", "warning", parent, TRUE, NULL, NULL);
292         generic_dialog_add_message(gd, icon_stock_id, heading, message);
293         generic_dialog_add_button(gd, GTK_STOCK_OK, NULL, file_util_warning_dialog_ok_cb, TRUE);
294         if (place_dialogs_under_mouse)
295                 {
296                 gtk_window_set_position(GTK_WINDOW(gd->dialog), GTK_WIN_POS_MOUSE);
297                 }
298         gtk_widget_show(gd->dialog);
299
300         return gd;
301 }
302
303 static gint filename_base_length(const gchar *name)
304 {
305         gint n;
306
307         if (!name) return 0;
308
309         n = strlen(name);
310
311         if (filter_name_exists(name))
312                 {
313                 const gchar *ext;
314
315                 ext = extension_from_path(name);
316                 if (ext) n -= strlen(ext);
317                 }
318
319         return n;
320 }
321
322
323 /*
324  *--------------------------------------------------------------------------
325  * Move and Copy routines
326  *--------------------------------------------------------------------------
327  */
328
329 /*
330  * Multi file move
331  */
332
333 static FileDataMult *file_data_multiple_new(GList *source_list, const gchar *dest, gint copy)
334 {
335         FileDataMult *fdm = g_new0(FileDataMult, 1);
336         fdm->confirm_all = FALSE;
337         fdm->confirmed = FALSE;
338         fdm->skip = FALSE;
339         fdm->source_list = source_list;
340         fdm->source_next = fdm->source_list;
341         fdm->dest_base = g_strdup(dest);
342         fdm->source = NULL;
343         fdm->dest = NULL;
344         fdm->copy = copy;
345         return fdm;
346 }
347
348 static void file_data_multiple_free(FileDataMult *fdm)
349 {
350         path_list_free(fdm->source_list);
351         g_free(fdm->dest_base);
352         g_free(fdm->dest);
353         g_free(fdm);
354 }
355
356 static void file_util_move_multiple(FileDataMult *fdm);
357
358 static void file_util_move_multiple_ok_cb(GenericDialog *gd, gpointer data)
359 {
360         FileDataMult *fdm = data;
361
362         fdm->confirmed = TRUE;
363
364         if (fdm->rename_auto)
365                 {
366                 gchar *buf;
367
368                 buf = unique_filename_simple(fdm->dest);
369                 if (buf)
370                         {
371                         g_free(fdm->dest);
372                         fdm->dest = buf;
373                         }
374                 else
375                         {
376                         /* unique failed? well, return to the overwrite prompt :( */
377                         fdm->confirmed = FALSE;
378                         }
379                 }
380         else if (fdm->rename)
381                 {
382                 const gchar *name;
383
384                 name = gtk_entry_get_text(GTK_ENTRY(fdm->rename_entry));
385                 if (strlen(name) == 0 ||
386                     strcmp(name, filename_from_path(fdm->source)) == 0)
387                         {
388                         fdm->confirmed = FALSE;
389                         }
390                 else
391                         {
392                         g_free(fdm->dest);
393                         fdm->dest = concat_dir_and_file(fdm->dest_base, name);
394                         fdm->confirmed = !isname(fdm->dest);
395                         }
396                 }
397
398         file_util_move_multiple(fdm);
399 }
400
401 static void file_util_move_multiple_all_cb(GenericDialog *gd, gpointer data)
402 {
403         FileDataMult *fdm = data;
404
405         fdm->confirm_all = TRUE;
406
407         if (fdm->rename_auto) fdm->rename_all = TRUE;
408
409         file_util_move_multiple(fdm);
410 }
411
412 static void file_util_move_multiple_skip_cb(GenericDialog *gd, gpointer data)
413 {
414         FileDataMult *fdm = data;
415
416         fdm->skip = TRUE;
417         fdm->confirmed = TRUE;
418
419         file_util_move_multiple(fdm);
420 }
421
422 static void file_util_move_multiple_skip_all_cb(GenericDialog *gd, gpointer data)
423 {
424         FileDataMult *fdm = data;
425
426         fdm->skip = TRUE;
427         fdm->confirm_all = TRUE;
428         file_util_move_multiple(fdm);
429 }
430
431 static void file_util_move_multiple_continue_cb(GenericDialog *gd, gpointer data)
432 {
433         FileDataMult *fdm = data;
434
435         fdm->confirmed = TRUE;
436         file_util_move_multiple(fdm);
437 }
438
439 static void file_util_move_multiple_cancel_cb(GenericDialog *gd, gpointer data)
440 {
441         FileDataMult *fdm = data;
442
443         file_data_multiple_free(fdm);
444 }
445
446 /* rename option */
447
448 static void file_util_move_multiple_rename_auto_cb(GtkWidget *widget, gpointer data)
449 {
450         GenericDialog *gd = data;
451         FileDataMult *fdm;
452
453         fdm = gd->data;
454
455         fdm->rename_auto = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
456         gtk_widget_set_sensitive(fdm->rename_box, !fdm->rename_auto);
457         gtk_widget_set_sensitive(fdm->rename_entry, (!fdm->rename_auto && fdm->rename));
458
459         if (fdm->rename_auto)
460                 {
461                 gchar *preview;
462
463                 preview = unique_filename_simple(fdm->dest);
464                 if (preview) gtk_entry_set_text(GTK_ENTRY(fdm->rename_entry), filename_from_path(preview));
465                 g_free(preview);
466                 }
467
468         gtk_widget_set_sensitive(fdm->yes_all_button, (fdm->rename_auto || !fdm->rename));
469 }
470
471 static void file_util_move_multiple_rename_cb(GtkWidget *widget, gpointer data)
472 {
473         GenericDialog *gd = data;
474         FileDataMult *fdm;
475
476         fdm = gd->data;
477
478         fdm->rename = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
479         gtk_widget_set_sensitive(fdm->rename_entry, fdm->rename);
480         gtk_widget_set_sensitive(fdm->yes_all_button, !fdm->rename);
481
482         if (fdm->rename)
483                 {
484                 const gchar *name;
485
486                 gtk_widget_grab_focus(fdm->rename_entry);
487
488                 name = gtk_entry_get_text(GTK_ENTRY(fdm->rename_entry));
489                 gtk_editable_select_region(GTK_EDITABLE(fdm->rename_entry), 0, filename_base_length(name));
490                 }
491 }
492
493 static GenericDialog *file_util_move_multiple_confirm_dialog(FileDataMult *fdm)
494 {
495         GenericDialog *gd;
496         GtkWidget *hbox;
497
498         gd = file_util_gen_dlg(_("Overwrite file"), "GQview", "dlg_confirm",
499                                 NULL, TRUE,
500                                 file_util_move_multiple_cancel_cb, fdm);
501
502         generic_dialog_add_message(gd, GTK_STOCK_DIALOG_QUESTION,
503                                    _("Overwrite file?"),
504                                    _("Replace existing file with new file."));
505         pref_spacer(gd->vbox, 0);
506
507         generic_dialog_add_button(gd, GTK_STOCK_YES, _("_Overwrite"), file_util_move_multiple_ok_cb, TRUE);
508         fdm->yes_all_button = generic_dialog_add_button(gd, NULL, _("Overwrite _all"),
509                                                         file_util_move_multiple_all_cb, FALSE);
510         generic_dialog_add_button(gd, GTK_STOCK_GOTO_LAST, _("S_kip all"), file_util_move_multiple_skip_all_cb, FALSE);
511         generic_dialog_add_button(gd, GTK_STOCK_GO_FORWARD, _("_Skip"), file_util_move_multiple_skip_cb, FALSE);
512         generic_dialog_add_image(gd, fdm->dest, _("Existing file"), fdm->source, _("New file"), TRUE);
513
514         /* rename option */
515
516         fdm->rename = FALSE;
517         fdm->rename_all = FALSE;
518         fdm->rename_auto = FALSE;
519
520         hbox = pref_box_new(gd->vbox, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_GAP);
521
522         fdm->rename_auto_box = gtk_check_button_new_with_label(_("Auto rename"));
523         g_signal_connect(G_OBJECT(fdm->rename_auto_box), "clicked",
524                          G_CALLBACK(file_util_move_multiple_rename_auto_cb), gd);
525         gtk_box_pack_start(GTK_BOX(hbox), fdm->rename_auto_box, FALSE, FALSE, 0);
526         gtk_widget_show(fdm->rename_auto_box);
527
528         hbox = pref_box_new(gd->vbox, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_GAP);
529
530         fdm->rename_box = gtk_check_button_new_with_label(_("Rename"));
531         g_signal_connect(G_OBJECT(fdm->rename_box), "clicked",
532                          G_CALLBACK(file_util_move_multiple_rename_cb), gd);
533         gtk_box_pack_start(GTK_BOX(hbox), fdm->rename_box, FALSE, FALSE, 0);
534         gtk_widget_show(fdm->rename_box);
535
536         fdm->rename_entry = gtk_entry_new();
537         gtk_entry_set_text(GTK_ENTRY(fdm->rename_entry), filename_from_path(fdm->dest));
538         gtk_widget_set_sensitive(fdm->rename_entry, FALSE);
539         gtk_box_pack_start(GTK_BOX(hbox), fdm->rename_entry, TRUE, TRUE, 0);
540         gtk_widget_show(fdm->rename_entry);
541
542         return gd;
543 }
544
545 static void file_util_move_multiple(FileDataMult *fdm)
546 {
547         while (fdm->dest || fdm->source_next)
548                 {
549                 gint success = FALSE;
550                 gint skip_file = FALSE;
551
552                 if (!fdm->dest)
553                         {
554                         GList *work = fdm->source_next;
555                         fdm->source = work->data;
556                         fdm->dest = concat_dir_and_file(fdm->dest_base, filename_from_path(fdm->source));
557                         fdm->source_next = work->next;
558                         fdm->confirmed = FALSE;
559                         }
560
561                 if (fdm->dest && fdm->source && strcmp(fdm->dest, fdm->source) == 0)
562                         {
563                         if (!fdm->confirmed)
564                                 {
565                                 GenericDialog *gd;
566                                 const gchar *title;
567                                 gchar *text;
568
569                                 if (fdm->copy)
570                                         {
571                                         title = _("Source to copy matches destination");
572                                         text = g_strdup_printf(_("Unable to copy file:\n%s\nto itself."), fdm->dest);
573                                         }
574                                 else
575                                         {
576                                         title = _("Source to move matches destination");
577                                         text = g_strdup_printf(_("Unable to move file:\n%s\nto itself."), fdm->dest);
578                                         }
579
580                                 gd = file_util_gen_dlg(title, "GQview", "dlg_confirm",
581                                                         NULL, TRUE,
582                                                         file_util_move_multiple_cancel_cb, fdm);
583                                 generic_dialog_add_message(gd, GTK_STOCK_DIALOG_WARNING, title, text);
584                                 g_free(text);
585                                 generic_dialog_add_button(gd, GTK_STOCK_GO_FORWARD, _("Co_ntinue"),
586                                                          file_util_move_multiple_continue_cb, TRUE);
587
588                                 gtk_widget_show(gd->dialog);
589                                 return;
590                                 }
591                         skip_file = TRUE;
592                         }
593                 else if (isfile(fdm->dest))
594                         {
595                         if (!fdm->confirmed && !fdm->confirm_all)
596                                 {
597                                 GenericDialog *gd;
598
599                                 gd = file_util_move_multiple_confirm_dialog(fdm);
600                                 gtk_widget_show(gd->dialog);
601                                 return;
602                                 }
603                         if (fdm->skip) skip_file = TRUE;
604                         }
605
606                 if (skip_file)
607                         {
608                         success = TRUE;
609                         if (!fdm->confirm_all) fdm->skip = FALSE;
610                         }
611                 else
612                         {
613                         gint try = TRUE;
614
615                         if (fdm->confirm_all && fdm->rename_all && isfile(fdm->dest))
616                                 {
617                                 gchar *buf;
618                                 buf = unique_filename_simple(fdm->dest);
619                                 if (buf)
620                                         {
621                                         g_free(fdm->dest);
622                                         fdm->dest = buf;
623                                         }
624                                 else
625                                         {
626                                         try = FALSE;
627                                         }
628                                 }
629                         if (try)
630                                 {
631                                 if (fdm->copy)
632                                         {
633                                         if (copy_file(fdm->source, fdm->dest))
634                                                 {
635                                                 success = TRUE;
636                                                 file_maint_copied(fdm->source, fdm->dest);
637                                                 }
638                                         }
639                                 else
640                                         {
641                                         if (move_file(fdm->source, fdm->dest))
642                                                 {
643                                                 success = TRUE;
644                                                 file_maint_moved(fdm->source, fdm->dest, fdm->source_list);
645                                                 }
646                                         }
647                                 }
648                         }
649
650                 if (!success)
651                         {
652                         GenericDialog *gd;
653                         const gchar *title;
654                         gchar *text;
655
656                         if (fdm->copy)
657                                 {
658                                 title = _("Error copying file");
659                                 text = g_strdup_printf(_("Unable to copy file:\n%s\nto:\n%s\nduring multiple file copy."), fdm->source, fdm->dest);
660                                 }
661                         else
662                                 {
663                                 title = _("Error moving file");
664                                 text = g_strdup_printf(_("Unable to move file:\n%s\nto:\n%s\nduring multiple file move."), fdm->source, fdm->dest);
665                                 }
666                         gd = file_util_gen_dlg(title, "GQview", "dlg_confirm",
667                                                 NULL, TRUE,
668                                                 file_util_move_multiple_cancel_cb, fdm);
669                         generic_dialog_add_message(gd, GTK_STOCK_DIALOG_WARNING, title, text);
670                         g_free(text);
671
672                         generic_dialog_add_button(gd, GTK_STOCK_GO_FORWARD, _("Co_ntinue"),
673                                                   file_util_move_multiple_continue_cb, TRUE);
674                         gtk_widget_show(gd->dialog);
675                         }
676
677                 g_free(fdm->dest);
678                 fdm->dest = NULL;
679
680                 if (!success) return;
681                 }
682
683         file_data_multiple_free(fdm);
684 }
685
686 /*
687  * Single file move
688  */
689
690 static FileDataSingle *file_data_single_new(const gchar *source, const gchar *dest, gint copy)
691 {
692         FileDataSingle *fds = g_new0(FileDataSingle, 1);
693         fds->confirmed = FALSE;
694         fds->source = g_strdup(source);
695         fds->dest = g_strdup(dest);
696         fds->copy = copy;
697         return fds;
698 }
699
700 static void file_data_single_free(FileDataSingle *fds)
701 {
702         g_free(fds->source);
703         g_free(fds->dest);
704         g_free(fds);
705 }
706
707 static void file_util_move_single(FileDataSingle *fds);
708
709 static void file_util_move_single_ok_cb(GenericDialog *gd, gpointer data)
710 {
711         FileDataSingle *fds = data;
712
713         fds->confirmed = TRUE;
714
715         if (fds->rename_auto)
716                 {
717                 gchar *buf;
718
719                 buf = unique_filename_simple(fds->dest);
720                 if (buf)
721                         {
722                         g_free(fds->dest);
723                         fds->dest = buf;
724                         }
725                 else
726                         {
727                         /* unique failed? well, return to the overwrite prompt :( */
728                         fds->confirmed = FALSE;
729                         }
730                 }
731         else if (fds->rename)
732                 {
733                 const gchar *name;
734
735                 name = gtk_entry_get_text(GTK_ENTRY(fds->rename_entry));
736                 if (strlen(name) == 0 ||
737                     strcmp(name, filename_from_path(fds->source)) == 0)
738                         {
739                         fds->confirmed = FALSE;
740                         }
741                 else
742                         {
743                         gchar *base;
744
745                         base = remove_level_from_path(fds->dest);
746                         g_free(fds->dest);
747                         fds->dest = concat_dir_and_file(base, name);
748                         fds->confirmed = !isname(fds->dest);
749
750                         g_free(base);
751                         }
752                 }
753
754         file_util_move_single(fds);
755 }
756
757 static void file_util_move_single_cancel_cb(GenericDialog *gd, gpointer data)
758 {
759         FileDataSingle *fds = data;
760
761         file_data_single_free(fds);
762 }
763
764 static void file_util_move_single_rename_auto_cb(GtkWidget *widget, gpointer data)
765 {
766         GenericDialog *gd = data;
767         FileDataSingle *fds;
768
769         fds = gd->data;
770
771         fds->rename_auto = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
772         gtk_widget_set_sensitive(fds->rename_box, !fds->rename_auto);
773         gtk_widget_set_sensitive(fds->rename_entry, (!fds->rename_auto && fds->rename));
774
775         if (fds->rename_auto)
776                 {
777                 gchar *preview;
778
779                 preview = unique_filename_simple(fds->dest);
780                 if (preview) gtk_entry_set_text(GTK_ENTRY(fds->rename_entry), filename_from_path(preview));
781                 g_free(preview);
782                 }
783 }
784
785 static void file_util_move_single_rename_cb(GtkWidget *widget, gpointer data)
786 {
787         GenericDialog *gd = data;
788         FileDataSingle *fds;
789
790         fds = gd->data;
791
792         fds->rename = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
793         gtk_widget_set_sensitive(fds->rename_entry, fds->rename);
794
795         if (fds->rename)
796                 {
797                 const gchar *name;
798
799                 gtk_widget_grab_focus(fds->rename_entry);
800
801                 name = gtk_entry_get_text(GTK_ENTRY(fds->rename_entry));
802                 gtk_editable_select_region(GTK_EDITABLE(fds->rename_entry), 0, filename_base_length(name));
803                 }
804 }
805
806 static void file_util_move_single(FileDataSingle *fds)
807 {
808         if (fds->dest && fds->source && strcmp(fds->dest, fds->source) == 0)
809                 {
810                 file_util_warning_dialog(_("Source matches destination"),
811                                          _("Source and destination are the same, operation cancelled."),
812                                          GTK_STOCK_DIALOG_INFO, NULL);
813                 }
814         else if (isfile(fds->dest) && !fds->confirmed)
815                 {
816                 GenericDialog *gd;
817                 GtkWidget *hbox;
818
819                 gd = file_util_gen_dlg(_("Overwrite file"), "GQview", "dlg_confirm",
820                                         NULL, TRUE,
821                                         file_util_move_single_cancel_cb, fds);
822
823                 generic_dialog_add_message(gd, GTK_STOCK_DIALOG_QUESTION,
824                                            _("Overwrite file?"),
825                                            _("Replace existing file with new file."));
826                 pref_spacer(gd->vbox, 0);
827
828                 generic_dialog_add_button(gd, GTK_STOCK_OK, _("_Overwrite"), file_util_move_single_ok_cb, TRUE);
829                 generic_dialog_add_image(gd, fds->dest, _("Existing file"), fds->source, _("New file"), TRUE);
830
831                 /* rename option */
832
833                 fds->rename = FALSE;
834                 fds->rename_auto = FALSE;
835
836                 hbox = pref_box_new(gd->vbox, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_GAP);
837
838                 fds->rename_auto_box = gtk_check_button_new_with_label(_("Auto rename"));
839                 g_signal_connect(G_OBJECT(fds->rename_auto_box), "clicked",
840                                  G_CALLBACK(file_util_move_single_rename_auto_cb), gd);
841                 gtk_box_pack_start(GTK_BOX(hbox), fds->rename_auto_box, FALSE, FALSE, 0);
842                 gtk_widget_show(fds->rename_auto_box);
843
844                 hbox = pref_box_new(gd->vbox, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_GAP);
845
846                 fds->rename_box = gtk_check_button_new_with_label(_("Rename"));
847                 g_signal_connect(G_OBJECT(fds->rename_box), "clicked",
848                                  G_CALLBACK(file_util_move_single_rename_cb), gd);
849                 gtk_box_pack_start(GTK_BOX(hbox), fds->rename_box, FALSE, FALSE, 0);
850                 gtk_widget_show(fds->rename_box);
851
852                 fds->rename_entry = gtk_entry_new();
853                 gtk_entry_set_text(GTK_ENTRY(fds->rename_entry), filename_from_path(fds->dest));
854                 gtk_widget_set_sensitive(fds->rename_entry, FALSE);
855                 gtk_box_pack_start(GTK_BOX(hbox), fds->rename_entry, TRUE, TRUE, 0);
856                 gtk_widget_show(fds->rename_entry);
857
858                 gtk_widget_show(gd->dialog);
859                 return;
860                 }
861         else
862                 {
863                 gint success = FALSE;
864                 if (fds->copy)
865                         {
866                         if (copy_file(fds->source, fds->dest))
867                                 {
868                                 success = TRUE;
869                                 file_maint_copied(fds->source, fds->dest);
870                                 }
871                         }
872                 else
873                         {
874                         if (move_file(fds->source, fds->dest))
875                                 {
876                                 success = TRUE;
877                                 file_maint_moved(fds->source, fds->dest, NULL);
878                                 }
879                         }
880                 if (!success)
881                         {
882                         gchar *title;
883                         gchar *text;
884                         if (fds->copy)
885                                 {
886                                 title = _("Error copying file");
887                                 text = g_strdup_printf(_("Unable to copy file:\n%s\nto:\n%s"), fds->source, fds->dest);
888                                 }
889                         else
890                                 {
891                                 title = _("Error moving file");
892                                 text = g_strdup_printf(_("Unable to move file:\n%s\nto:\n%s"), fds->source, fds->dest);
893                                 }
894                         file_util_warning_dialog(title, text, GTK_STOCK_DIALOG_ERROR, NULL);
895                         g_free(text);
896                         }
897                 }
898
899         file_data_single_free(fds);
900 }
901
902 /*
903  * file move dialog
904  */
905
906 static void file_util_move_do(FileDialog *fd)
907 {
908         file_dialog_sync_history(fd, TRUE);
909
910         if (fd->multiple_files)
911                 {
912                 file_util_move_multiple(file_data_multiple_new(fd->source_list, fd->dest_path, fd->type));
913                 fd->source_list = NULL;
914                 }
915         else
916                 {
917                 if (isdir(fd->dest_path))
918                         {
919                         gchar *buf = concat_dir_and_file(fd->dest_path, filename_from_path(fd->source_path));
920                         gtk_entry_set_text(GTK_ENTRY(fd->entry), buf);
921                         g_free(buf);
922                         }
923                 file_util_move_single(file_data_single_new(fd->source_path, fd->dest_path, fd->type));
924                 }
925
926         file_dialog_close(fd);
927 }
928
929 static void file_util_move_check(FileDialog *fd)
930 {
931         if (fd->dest_path && strcmp(fd->dest_path, "~") == 0)
932                 {
933                 gtk_entry_set_text(GTK_ENTRY(fd->entry), homedir());
934                 }
935
936         if (fd->multiple_files && !isdir(fd->dest_path))
937                 {
938                 if (isfile(fd->dest_path))
939                         {
940                         file_util_warning_dialog(_("Invalid destination"),
941                                                  _("When operating with multiple files, please select\na folder, not a file."),
942                                                  GTK_STOCK_DIALOG_INFO, NULL);
943                         }
944                 else
945                         file_util_warning_dialog(_("Invalid folder"),
946                                                  _("Please select an existing folder."),
947                                                  GTK_STOCK_DIALOG_INFO, NULL);
948                 return;
949                 }
950
951         if (!fd->dest_path || fd->dest_path[0] != '/')
952                 {
953                 if (fd->source_path)
954                         {
955                         gchar *base;
956                         gchar *path;
957
958                         base = remove_level_from_path(fd->source_path);
959                         path = concat_dir_and_file(base, fd->dest_path);
960
961                         gtk_entry_set_text(GTK_ENTRY(fd->entry), path);
962
963                         g_free(path);
964                         g_free(base);
965                         }
966                 return;
967                 }
968
969         file_util_move_do(fd);
970 }
971
972 static void file_util_move_cb(FileDialog *fd, gpointer data)
973 {
974         file_util_move_check(fd);
975 }
976
977 static void file_util_move_cancel_cb(FileDialog *fd, gpointer data)
978 {
979         file_dialog_close(fd);
980 }
981
982 static void real_file_util_move(const gchar *source_path, GList *source_list,
983                                 const gchar *dest_path, gint copy, GtkWidget *parent)
984 {
985         FileDialog *fd;
986         GtkWidget *label;
987         gchar *path = NULL;
988         gint multiple;
989         const gchar *text;
990         const gchar *title;
991         const gchar *op_text;
992         const gchar *stock_id;
993
994         if (!source_path && !source_list) return;
995
996         if (source_path)
997                 {
998                 path = g_strdup(source_path);
999                 multiple = FALSE;
1000                 }
1001         else if (source_list->next)
1002                 {
1003                 multiple = TRUE;
1004                 }
1005         else
1006                 {
1007                 path = g_strdup(source_list->data);
1008                 path_list_free(source_list);
1009                 source_list = NULL;
1010                 multiple = FALSE;
1011                 }
1012
1013         if (copy)
1014                 {
1015                 title = _("Copy - GQview");
1016                 op_text = _("_Copy");
1017                 if (path)
1018                         {
1019                         text = _("Copy file");
1020                         }
1021                 else
1022                         {
1023                         text = _("Copy multiple files");
1024                         }
1025                 stock_id = GTK_STOCK_COPY;
1026                 }
1027         else
1028                 {
1029                 title = _("Move - GQview");
1030                 op_text = _("_Move");
1031                 if (path)
1032                         {
1033                         text = _("Move file");
1034                         }
1035                 else
1036                         {
1037                         text = _("Move multiple files");
1038                         }
1039                 stock_id = GTK_STOCK_OK;
1040                 }
1041
1042         fd = file_util_file_dlg(title, "GQview", "dlg_copymove", parent,
1043                                 file_util_move_cancel_cb, NULL);
1044         generic_dialog_add_message(GENERIC_DIALOG(fd), NULL, text, NULL);
1045
1046         if (path)
1047                 {
1048                 GtkWidget *box;
1049
1050                 box = pref_box_new(GENERIC_DIALOG(fd)->vbox, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
1051                 pref_label_new(box, _("File name:"));
1052                 pref_label_new(box, filename_from_path(path));
1053                 }
1054
1055         label = pref_label_new(GENERIC_DIALOG(fd)->vbox, _("Choose the destination folder."));
1056         gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
1057         pref_spacer(GENERIC_DIALOG(fd)->vbox, 0);
1058
1059         file_dialog_add_button(fd, stock_id, op_text, file_util_move_cb, TRUE);
1060
1061         file_dialog_add_path_widgets(fd, NULL, dest_path, "move_copy", NULL, NULL);
1062
1063         fd->type = copy;
1064         fd->source_path = path;
1065         fd->source_list = source_list;
1066         fd->multiple_files = multiple;
1067
1068         gtk_widget_show(GENERIC_DIALOG(fd)->dialog);
1069 }
1070
1071 void file_util_move(const gchar *source_path, GList *source_list, const gchar *dest_path, GtkWidget *parent)
1072 {
1073         real_file_util_move(source_path, source_list, dest_path, FALSE, parent);
1074 }
1075
1076 void file_util_copy(const gchar *source_path, GList *source_list, const gchar *dest_path, GtkWidget *parent)
1077 {
1078         real_file_util_move(source_path, source_list, dest_path, TRUE, parent);
1079 }
1080
1081 void file_util_move_simple(GList *list, const gchar *dest_path)
1082 {
1083         if (!list) return;
1084         if (!dest_path)
1085                 {
1086                 path_list_free(list);
1087                 return;
1088                 }
1089
1090         if (!list->next)
1091                 {
1092                 const gchar *source;
1093                 gchar *dest;
1094
1095                 source = list->data;
1096                 dest = concat_dir_and_file(dest_path, filename_from_path(source));
1097
1098                 file_util_move_single(file_data_single_new(source, dest, FALSE));
1099                 g_free(dest);
1100                 path_list_free(list);
1101                 return;
1102                 }
1103
1104         file_util_move_multiple(file_data_multiple_new(list, dest_path, FALSE));
1105 }
1106
1107 void file_util_copy_simple(GList *list, const gchar *dest_path)
1108 {
1109         if (!list) return;
1110         if (!dest_path)
1111                 {
1112                 path_list_free(list);
1113                 return;
1114                 }
1115
1116         if (!list->next)
1117                 {
1118                 const gchar *source;
1119                 gchar *dest;
1120
1121                 source = list->data;
1122                 dest = concat_dir_and_file(dest_path, filename_from_path(source));
1123
1124                 file_util_move_single(file_data_single_new(source, dest, TRUE));
1125                 g_free(dest);
1126                 path_list_free(list);
1127                 return;
1128                 }
1129
1130         file_util_move_multiple(file_data_multiple_new(list, dest_path, TRUE));
1131 }
1132
1133 /*
1134  *--------------------------------------------------------------------------
1135  * Safe Delete
1136  *--------------------------------------------------------------------------
1137  */
1138
1139 static gint file_util_safe_number(gint64 free_space)
1140 {
1141         gint n = 0;
1142         gint64 total = 0;
1143         GList *list;
1144         GList *work;
1145         gint sorted = FALSE;
1146         gint warned = FALSE;
1147
1148         if (!filelist_read(safe_delete_path, &list, NULL)) return 0;
1149
1150         work = list;
1151         while (work)
1152                 {
1153                 FileData *fd;
1154                 gint v;
1155                
1156                 fd = work->data;
1157                 work = work->next;
1158
1159                 v = (gint)strtol(fd->name, NULL, 10);
1160                 if (v >= n) n = v + 1;
1161
1162                 total += fd->size;
1163                 }
1164
1165         while (list &&
1166                (free_space < 0 || total + free_space > (gint64)safe_delete_size * 1048576) )
1167                 {
1168                 FileData *fd;
1169
1170                 if (!sorted)
1171                         {
1172                         list = filelist_sort(list, SORT_NAME, TRUE);
1173                         sorted = TRUE;
1174                         }
1175
1176                 fd = list->data;
1177                 list = g_list_remove(list, fd);
1178
1179                 if (debug) printf("expunging from trash for space: %s\n", fd->name);
1180                 if (!unlink_file(fd->path) && !warned)
1181                         {
1182                         file_util_warning_dialog(_("Delete failed"),
1183                                                  _("Unable to remove old file from trash folder"),
1184                                                  GTK_STOCK_DIALOG_WARNING, NULL);
1185                         warned = TRUE;
1186                         }
1187                 total -= fd->size;
1188                 file_data_free(fd);
1189                 }
1190
1191         filelist_free(list);
1192
1193         return n;
1194 }
1195
1196 void file_util_trash_clear(void)
1197 {
1198         file_util_safe_number(-1);
1199 }
1200
1201 static gchar *file_util_safe_dest(const gchar *path)
1202 {
1203         gint n;
1204
1205         n = file_util_safe_number(filesize(path));
1206         return g_strdup_printf("%s/%06d_%s", safe_delete_path, n, filename_from_path(path));
1207 }
1208
1209 static void file_util_safe_del_toggle_cb(GtkWidget *button, gpointer data)
1210 {
1211         safe_delete_enable = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button));
1212 }
1213
1214 static void file_util_safe_del_close_cb(GtkWidget *dialog, gpointer data)
1215 {
1216         GenericDialog **gd = data;
1217
1218         *gd = NULL;
1219 }
1220
1221 static gint file_util_unlink(const gchar *path)
1222 {
1223         static GenericDialog *gd = NULL;
1224         gchar *result = NULL;
1225         gint success = TRUE;
1226
1227         if (!isfile(path)) return FALSE;
1228
1229         if (!safe_delete_enable)
1230                 {
1231                 return unlink_file(path);
1232                 }
1233
1234         if (!isdir(safe_delete_path))
1235                 {
1236                 if (debug) printf("creating trash: %s\n", safe_delete_path);
1237                 if (!safe_delete_path || !mkdir_utf8(safe_delete_path, 0755))
1238                         {
1239                         result = _("Could not create folder");
1240                         success = FALSE;
1241                         }
1242                 }
1243
1244         if (success)
1245                 {
1246                 gchar *dest;
1247
1248                 dest = file_util_safe_dest(path);
1249                 if (dest)
1250                         {
1251                         if (debug) printf("safe deleting %s to %s\n", path, dest);
1252                         success = move_file(path, dest);
1253                         }
1254                 else
1255                         {
1256                         success = FALSE;
1257                         }
1258
1259                 if (!success && !access_file(path, W_OK))
1260                         {
1261                         result = _("Permission denied");
1262                         }
1263                 g_free(dest);
1264                 }
1265
1266         if (result && !gd)
1267                 {
1268                 GtkWidget *button;
1269                 gchar *buf;
1270
1271                 buf = g_strdup_printf(_("Unable to access or create the trash folder.\n\"%s\""), safe_delete_path);
1272                 gd = file_util_warning_dialog(result, buf, GTK_STOCK_DIALOG_WARNING, NULL);
1273                 g_free(buf);
1274
1275                 button = gtk_check_button_new_with_label(_("Turn off safe delete"));
1276                 g_signal_connect(G_OBJECT(button), "toggled",
1277                                  G_CALLBACK(file_util_safe_del_toggle_cb), NULL);
1278                 gtk_box_pack_start(GTK_BOX(gd->vbox), button, FALSE, FALSE, 0);
1279                 gtk_widget_show(button);
1280
1281                 g_signal_connect(G_OBJECT(gd->dialog), "destroy",
1282                                  G_CALLBACK(file_util_safe_del_close_cb), &gd);
1283                 }
1284
1285         return success;
1286 }
1287
1288 static void box_append_safe_delete_status(GenericDialog *gd)
1289 {
1290         GtkWidget *label;
1291         gchar *buf;
1292
1293         buf = g_strdup_printf(_("Safe delete: %s"), (safe_delete_enable) ? _("on") : _("off"));
1294         label = pref_label_new(gd->vbox, buf);
1295         g_free(buf);
1296
1297         gtk_misc_set_alignment(GTK_MISC(label), 1.0, 0.5);
1298         gtk_widget_set_sensitive(label, FALSE);
1299 }
1300
1301 /*
1302  *--------------------------------------------------------------------------
1303  * Delete routines
1304  *--------------------------------------------------------------------------
1305  */
1306
1307 /*
1308  * delete multiple files
1309  */
1310
1311 static void file_util_delete_multiple_ok_cb(GenericDialog *gd, gpointer data);
1312 static void file_util_delete_multiple_cancel_cb(GenericDialog *gd, gpointer data);
1313
1314 static void file_util_delete_multiple_ok_cb(GenericDialog *gd, gpointer data)
1315 {
1316         GList *source_list = data;
1317
1318         while (source_list)
1319                 {
1320                 gchar *path = source_list->data;
1321
1322                 source_list = g_list_remove(source_list, path);
1323
1324                 if (!file_util_unlink(path))
1325                         {
1326                         if (source_list)
1327                                 {
1328                                 GenericDialog *d;
1329                                 gchar *text;
1330
1331                                 d = file_util_gen_dlg(_("Delete failed"), "GQview", "dlg_confirm",
1332                                                       NULL, TRUE,
1333                                                       file_util_delete_multiple_cancel_cb, source_list);
1334
1335                                 text = g_strdup_printf(_("Unable to delete file:\n %s\n Continue multiple delete operation?"), path);
1336                                 generic_dialog_add_message(d, GTK_STOCK_DIALOG_WARNING, NULL, text);
1337                                 g_free(text);
1338
1339                                 generic_dialog_add_button(d, GTK_STOCK_GO_FORWARD, _("Co_ntinue"),
1340                                                           file_util_delete_multiple_ok_cb, TRUE);
1341                                 gtk_widget_show(d->dialog);
1342                                 }
1343                         else
1344                                 {
1345                                 gchar *text;
1346                                 
1347                                 text = g_strdup_printf(_("Unable to delete file:\n%s"), path);
1348                                 file_util_warning_dialog(_("Delete failed"), text, GTK_STOCK_DIALOG_ERROR, NULL);
1349                                 g_free(text);
1350                                 }
1351                         g_free(path);
1352                         return;
1353                         }
1354                 else
1355                         {
1356                         file_maint_removed(path, source_list);
1357                         }
1358                 g_free(path);
1359                 }
1360 }
1361
1362 static void file_util_delete_multiple_cancel_cb(GenericDialog *gd, gpointer data)
1363 {
1364         GList *source_list = data;
1365
1366         path_list_free(source_list);
1367 }
1368
1369 static void file_util_delete_multiple_review_skip(GenericDialog *gd, gint next)
1370 {
1371         GtkWidget *button_back;
1372         GtkWidget *button_next;
1373         GtkWidget *button_label;
1374         GList *list;
1375         GList *list_point;
1376         const gchar *path;
1377         gchar *buf;
1378
1379         list = gd->data;
1380         button_back = g_object_get_data(G_OBJECT(gd->dialog), "button_back");
1381         button_next = g_object_get_data(G_OBJECT(gd->dialog), "button_next");
1382         button_label = g_object_get_data(G_OBJECT(gd->dialog), "button_label");
1383         list_point = g_object_get_data(G_OBJECT(gd->dialog), "list_point");
1384
1385         if (!list || !button_label) return;
1386
1387         if (list_point)
1388                 {
1389                 if (next)
1390                         {
1391                         if (list_point->next) list_point = list_point->next;
1392                         }
1393                 else
1394                         {
1395                         if (list_point->prev) list_point = list_point->prev;
1396                         }
1397                 }
1398         else
1399                 {
1400                 list_point = list;
1401                 }
1402
1403         if (!list_point) return;
1404
1405         path = list_point->data;
1406         buf = g_strdup_printf(_("File %d of %d"),
1407                               g_list_index(list, (gpointer)path) + 1,
1408                               g_list_length(list));
1409         gtk_label_set_text(GTK_LABEL(button_label), buf);
1410         g_free(buf);
1411
1412         gtk_widget_set_sensitive(button_back, (list_point->prev != NULL) );
1413         gtk_widget_set_sensitive(button_next, (list_point->next != NULL) );
1414
1415         generic_dialog_image_set(gd, path);
1416
1417         g_object_set_data(G_OBJECT(gd->dialog), "list_point", list_point);
1418 }
1419
1420 static void file_util_delete_multiple_review_back(GtkWidget *button, gpointer data)
1421 {
1422         GenericDialog *gd = data;
1423
1424         file_util_delete_multiple_review_skip(gd, FALSE);
1425 }
1426
1427 static void file_util_delete_multiple_review_next(GtkWidget *button, gpointer data)
1428 {
1429         GenericDialog *gd = data;
1430
1431         file_util_delete_multiple_review_skip(gd, TRUE);
1432 }
1433
1434 static void file_util_delete_multiple_review_button_cb(ImageWindow *imd, gint button, guint32 time,
1435                                                        gdouble x, gdouble y, guint state, gpointer data)
1436 {
1437         if (button == 1)
1438                 {
1439                 file_util_delete_multiple_review_next(NULL, data);
1440                 }
1441         else if (button == 2 || button == 3)
1442                 {
1443                 file_util_delete_multiple_review_back(NULL, data);
1444                 }
1445 }
1446
1447 static void file_util_delete_multiple_review_scroll_cb(ImageWindow *imd, GdkScrollDirection direction, guint32 time,
1448                                                        gdouble x, gdouble y, guint state, gpointer data)
1449 {
1450         if (direction == GDK_SCROLL_UP)
1451                 {
1452                 file_util_delete_multiple_review_back(NULL, data);
1453                 }
1454         else if (direction == GDK_SCROLL_DOWN)
1455                 {
1456                 file_util_delete_multiple_review_next(NULL, data);
1457                 }
1458 }
1459
1460 static void file_util_delete_multiple(GList *source_list, GtkWidget *parent)
1461 {
1462         if (!confirm_delete)
1463                 {
1464                 file_util_delete_multiple_ok_cb(NULL, source_list);
1465                 }
1466         else
1467                 {
1468                 GenericDialog *gd;
1469                 GtkWidget *hbox;
1470                 GtkWidget *button;
1471                 GtkWidget *label;
1472                 ImageWindow *imd;
1473                 gchar *buf;
1474
1475                 gd = file_util_gen_dlg(_("Delete files - GQview"),
1476                                         "GQview", "dlg_confirm", parent, TRUE,
1477                                         file_util_delete_multiple_cancel_cb, source_list);
1478
1479                 generic_dialog_add_message(gd, NULL, _("Delete multiple files"), NULL);
1480
1481                 generic_dialog_add_image(gd, NULL, NULL, NULL, NULL, TRUE);
1482                 imd = g_object_get_data(G_OBJECT(gd->dialog), "img_image");
1483                 image_set_button_func(imd, file_util_delete_multiple_review_button_cb, gd);
1484                 image_set_scroll_func(imd, file_util_delete_multiple_review_scroll_cb, gd);
1485
1486                 hbox = pref_box_new(gd->vbox, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
1487
1488                 button = pref_button_new(hbox, GTK_STOCK_GO_BACK, NULL, TRUE,
1489                                          G_CALLBACK(file_util_delete_multiple_review_back), gd);
1490                 gtk_widget_set_sensitive(button, FALSE);
1491                 g_object_set_data(G_OBJECT(gd->dialog), "button_back", button);
1492
1493                 button = pref_button_new(hbox, GTK_STOCK_GO_FORWARD, NULL, TRUE,
1494                                          G_CALLBACK(file_util_delete_multiple_review_next), gd);
1495                 g_object_set_data(G_OBJECT(gd->dialog), "button_next", button);
1496
1497                 buf = g_strdup_printf(_("Review %d files"), g_list_length(source_list) );
1498                 label = pref_label_new(hbox, buf);
1499                 g_free(buf);
1500                 g_object_set_data(G_OBJECT(gd->dialog), "button_label", label);
1501
1502                 box_append_safe_delete_status(gd);
1503
1504                 generic_dialog_add_button(gd, GTK_STOCK_DELETE, NULL, file_util_delete_multiple_ok_cb, TRUE);
1505
1506                 gtk_widget_show(gd->dialog);
1507                 }
1508 }
1509
1510 /*
1511  * delete single file
1512  */
1513
1514 static void file_util_delete_ok_cb(GenericDialog *gd, gpointer data)
1515 {
1516         gchar *path = data;
1517
1518         if (!file_util_unlink(path))
1519                 {
1520                 gchar *text = g_strdup_printf(_("Unable to delete file:\n%s"), path);
1521                 file_util_warning_dialog(_("File deletion failed"), text, GTK_STOCK_DIALOG_ERROR, NULL);
1522                 g_free(text);
1523                 }
1524         else
1525                 {
1526                 file_maint_removed(path, NULL);
1527                 }
1528
1529         g_free(path);
1530 }
1531
1532 static void file_util_delete_cancel_cb(GenericDialog *gd, gpointer data)
1533 {
1534         gchar *path = data;
1535
1536         g_free(path);
1537 }
1538
1539 static void file_util_delete_single(const gchar *path, GtkWidget *parent)
1540 {
1541         gchar *buf = g_strdup(path);
1542
1543         if (!confirm_delete)
1544                 {
1545                 file_util_delete_ok_cb(NULL, buf);
1546                 }
1547         else
1548                 {
1549                 GenericDialog *gd;
1550                 GtkWidget *table;
1551                 gchar *base;
1552
1553                 gd = file_util_gen_dlg(_("Delete file - GQview"), "GQview", "dlg_confirm",
1554                                         parent, TRUE,
1555                                         file_util_delete_cancel_cb, buf);
1556
1557                 generic_dialog_add_message(gd, NULL, _("Delete file?"), NULL);
1558
1559                 table = pref_table_new(gd->vbox, 2, 2, FALSE, FALSE);
1560
1561                 pref_table_label(table, 0, 0, _("File name:"), 1.0);
1562                 pref_table_label(table, 1, 0, filename_from_path(path), 0.0);
1563
1564                 pref_table_label(table, 0, 1, _("Location:"), 1.0);
1565
1566                 base = remove_level_from_path(path);
1567                 pref_table_label(table, 1, 1, base, 0.0);
1568                 g_free(base);
1569
1570                 generic_dialog_add_image(gd, path, NULL, NULL, NULL, FALSE);
1571
1572                 box_append_safe_delete_status(gd);
1573
1574                 generic_dialog_add_button(gd, GTK_STOCK_DELETE, NULL, file_util_delete_ok_cb, TRUE);
1575
1576                 gtk_widget_show(gd->dialog);
1577                 }
1578 }
1579
1580 void file_util_delete(const gchar *source_path, GList *source_list, GtkWidget *parent)
1581 {
1582         if (!source_path && !source_list) return;
1583
1584         if (source_path)
1585                 {
1586                 file_util_delete_single(source_path, parent);
1587                 }
1588         else if (!source_list->next)
1589                 {
1590                 file_util_delete_single(source_list->data, parent);
1591                 path_list_free(source_list);
1592                 }
1593         else
1594                 {
1595                 file_util_delete_multiple(source_list, parent);
1596                 }
1597 }
1598
1599 /*
1600  *--------------------------------------------------------------------------
1601  * Rename routines
1602  *--------------------------------------------------------------------------
1603  */
1604
1605 /*
1606  * rename multiple files
1607  */
1608
1609 enum {
1610         RENAME_COLUMN_PATH = 0,
1611         RENAME_COLUMN_NAME,
1612         RENAME_COLUMN_PREVIEW,
1613         RENAME_COLUMN_COUNT
1614 };
1615
1616 typedef enum {
1617         RENAME_TYPE_MANUAL = 0,
1618         RENAME_TYPE_FORMATTED,
1619         RENAME_TYPE_AUTO
1620 } RenameType;
1621
1622 typedef struct _RenameDataMult RenameDataMult;
1623 struct _RenameDataMult
1624 {
1625         FileDialog *fd;
1626
1627         RenameType rename_type;
1628
1629         GtkWidget *listview;
1630         GtkWidget *combo_type;
1631
1632         GtkWidget *rename_box;
1633         GtkWidget *rename_label;
1634         GtkWidget *rename_entry;
1635
1636         GtkWidget *auto_box;
1637         GtkWidget *auto_entry_front;
1638         GtkWidget *auto_spin_start;
1639         GtkWidget *auto_spin_pad;
1640         GtkWidget *auto_entry_end;
1641
1642         GtkWidget *format_box;
1643         GtkWidget *format_entry;
1644         GtkWidget *format_spin;
1645
1646         ImageWindow *imd;
1647
1648         gint update_idle_id;
1649 };
1650
1651 static void file_util_rename_multiple(RenameDataMult *rd);
1652
1653 static void file_util_rename_multiple_ok_cb(GenericDialog *gd, gpointer data)
1654 {
1655         RenameDataMult *rd = data;
1656         GtkWidget *dialog;
1657
1658         dialog = GENERIC_DIALOG(rd->fd)->dialog;
1659         if (!GTK_WIDGET_VISIBLE(dialog)) gtk_widget_show(dialog);
1660
1661         rd->fd->type = TRUE;
1662         file_util_rename_multiple(rd);
1663 }
1664
1665 static void file_util_rename_multiple_cancel_cb(GenericDialog *gd, gpointer data)
1666 {
1667         RenameDataMult *rd = data;
1668         GtkWidget *dialog;
1669
1670         dialog = GENERIC_DIALOG(rd->fd)->dialog;
1671         if (!GTK_WIDGET_VISIBLE(dialog)) gtk_widget_show(dialog);
1672 }
1673
1674 static gint file_util_rename_multiple_find_row(RenameDataMult *rd, const gchar *path, GtkTreeIter *iter)
1675 {
1676         GtkTreeModel *store;
1677         gint valid;
1678         gint row = 0;
1679
1680         store = gtk_tree_view_get_model(GTK_TREE_VIEW(rd->listview));
1681         valid = gtk_tree_model_get_iter_first(store, iter);
1682         while (valid)
1683                 {
1684                 gchar *path_n;
1685                 gint ret;
1686
1687                 gtk_tree_model_get(GTK_TREE_MODEL(store), iter, RENAME_COLUMN_PATH, &path_n, -1);
1688                 ret = (strcmp(path_n, path) == 0);
1689                 g_free(path_n);
1690                 if (ret) return row;
1691
1692                 valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(store), iter);
1693                 row++;
1694                 }
1695
1696         return -1;
1697 }
1698
1699 static void file_util_rename_multiple(RenameDataMult *rd)
1700 {
1701         FileDialog *fd;
1702
1703         fd = rd->fd;
1704
1705         if (isfile(fd->dest_path) && !fd->type)
1706                 {
1707                 GenericDialog *gd;
1708
1709                 gd = file_util_gen_dlg(_("Overwrite file"), "GQview", "dlg_confirm",
1710                                         NULL, TRUE,
1711                                         file_util_rename_multiple_cancel_cb, rd);
1712
1713                 generic_dialog_add_message(gd, GTK_STOCK_DIALOG_QUESTION,
1714                                            _("Overwrite file?"),
1715                                            _("Replace existing file by renaming new file."));
1716                 pref_spacer(gd->vbox, 0);
1717
1718                 generic_dialog_add_button(gd, GTK_STOCK_OK, _("_Overwrite"), file_util_rename_multiple_ok_cb, TRUE);
1719                 generic_dialog_add_image(gd, fd->dest_path, _("Existing file"), fd->source_path, _("New file"), TRUE);
1720
1721                 gtk_widget_hide(GENERIC_DIALOG(fd)->dialog);
1722
1723                 gtk_widget_show(gd->dialog);
1724                 return;
1725                 }
1726         else
1727                 {
1728                 if (!rename_file(fd->source_path, fd->dest_path))
1729                         {
1730                         gchar *text = g_strdup_printf(_("Unable to rename file:\n%s\n to:\n%s"),
1731                                                       filename_from_path(fd->source_path),
1732                                                       filename_from_path(fd->dest_path));
1733                         file_util_warning_dialog(_("Error renaming file"), text, GTK_STOCK_DIALOG_ERROR, NULL);
1734                         g_free(text);
1735                         }
1736                 else
1737                         {
1738                         GtkTreeModel *store;
1739                         GtkTreeIter iter;
1740                         GtkTreeIter next;
1741                         gint row;
1742
1743                         file_maint_renamed(fd->source_path, fd->dest_path);
1744
1745                         store = gtk_tree_view_get_model(GTK_TREE_VIEW(rd->listview));
1746                         row = file_util_rename_multiple_find_row(rd, rd->fd->source_path, &iter);
1747
1748                         if (row >= 0 &&
1749                             (gtk_tree_model_iter_nth_child(store, &next, NULL, row + 1) ||
1750                             (row > 0 && gtk_tree_model_iter_nth_child(store, &next, NULL, row - 1)) ) )
1751                                 {
1752                                 GtkTreeSelection *selection;
1753
1754                                 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(rd->listview));
1755                                 gtk_tree_selection_select_iter(selection, &next);
1756                                 gtk_list_store_remove(GTK_LIST_STORE(store), &iter);
1757                                 }
1758                         else
1759                                 {
1760                                 if (debug) printf("closed by #%d\n", row);
1761
1762                                 file_dialog_close(rd->fd);
1763                                 }
1764                         }
1765                 }
1766 }
1767
1768 /* format: * = filename without extension, ## = number position, extension is kept */
1769 static gchar *file_util_rename_multiple_auto_format_name(const gchar *format, const gchar *name, gint n)
1770 {
1771         gchar *new_name;
1772         gchar *parsed;
1773         const gchar *ext;
1774         gchar *middle;
1775         gchar *tmp;
1776         gchar *pad_start;
1777         gchar *pad_end;
1778         gint padding;
1779
1780         if (!format || !name) return NULL;
1781
1782         tmp = g_strdup(format);
1783         pad_start = strchr(tmp, '#');
1784         if (pad_start)
1785                 {
1786                 pad_end = pad_start;
1787                 padding = 0;
1788                 while (*pad_end == '#')
1789                         {
1790                         pad_end++;
1791                         padding++;
1792                         }
1793                 *pad_start = '\0';
1794
1795                 parsed = g_strdup_printf("%s%0*d%s", tmp, padding, n, pad_end);
1796                 g_free(tmp);
1797                 }
1798         else
1799                 {
1800                 parsed = tmp;
1801                 }
1802
1803         ext = extension_from_path(name);
1804
1805         middle = strchr(parsed, '*');
1806         if (middle)
1807                 {
1808                 gchar *base;
1809
1810                 *middle = '\0';
1811                 middle++;
1812
1813                 base = remove_extension_from_path(name);
1814                 new_name = g_strconcat(parsed, base, middle, ext, NULL);
1815                 g_free(base);
1816                 }
1817         else
1818                 {
1819                 new_name = g_strconcat(parsed, ext, NULL);
1820                 }
1821
1822         g_free(parsed);
1823
1824         return new_name;
1825 }
1826
1827 static void file_util_rename_multiple_auto(RenameDataMult *rd)
1828 {
1829         const gchar *front;
1830         const gchar *end;
1831         const gchar *format;
1832         gint start_n;
1833         gint padding;
1834         gint n;
1835         GtkTreeModel *store;
1836         GtkTreeIter iter;
1837         gint valid;
1838         gint success;
1839
1840         front = gtk_entry_get_text(GTK_ENTRY(rd->auto_entry_front));
1841         end = gtk_entry_get_text(GTK_ENTRY(rd->auto_entry_end));
1842         padding = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(rd->auto_spin_pad));
1843
1844         format = gtk_entry_get_text(GTK_ENTRY(rd->format_entry));
1845
1846         if (rd->rename_type == RENAME_TYPE_FORMATTED)
1847                 {
1848                 start_n = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(rd->format_spin));
1849
1850                 if (!format ||
1851                     (strchr(format, '*') == NULL && strchr(format, '#') == NULL))
1852                         {
1853                         file_util_warning_dialog(_("Auto rename"),
1854                                _("Format must include at least one of the symbol characters '*' or '#'.\n"),
1855                                GTK_STOCK_DIALOG_WARNING, NULL);
1856                         return;
1857                         }
1858
1859                 history_combo_append_history(rd->format_entry, NULL);
1860                 }
1861         else
1862                 {
1863                 start_n = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(rd->auto_spin_start));
1864
1865                 history_combo_append_history(rd->auto_entry_front, NULL);
1866                 history_combo_append_history(rd->auto_entry_end, NULL);
1867                 }
1868
1869         store = gtk_tree_view_get_model(GTK_TREE_VIEW(rd->listview));
1870
1871         /* first check for name conflicts */
1872         success = TRUE;
1873         n = start_n;
1874         valid = gtk_tree_model_get_iter_first(store, &iter);
1875         while (valid && success)
1876                 {
1877                 gchar *dest;
1878                 gchar *base;
1879                 gchar *path;
1880
1881                 gtk_tree_model_get(store, &iter, RENAME_COLUMN_PATH, &path, -1);
1882                 base = remove_level_from_path(path);
1883
1884                 if (rd->rename_type == RENAME_TYPE_FORMATTED)
1885                         {
1886                         gchar *new_name;
1887
1888                         new_name = file_util_rename_multiple_auto_format_name(format, filename_from_path(path), n);
1889                         dest = g_strconcat(base, "/", new_name, NULL);
1890                         g_free(new_name);
1891                         }
1892                 else
1893                         {
1894                         dest = g_strdup_printf("%s/%s%0*d%s", base, front, padding, n, end);
1895                         }
1896
1897                 if (isname(dest)) success = FALSE;
1898
1899                 g_free(dest);
1900                 g_free(base);
1901                 g_free(path);
1902
1903                 n++;
1904                 valid = gtk_tree_model_iter_next(store, &iter);
1905                 }
1906
1907         if (!success)
1908                 {
1909                 file_util_warning_dialog(_("Auto rename"),
1910                                _("Can not auto rename with the selected\nnumber set, one or more files exist that\nmatch the resulting name list.\n"),
1911                                GTK_STOCK_DIALOG_WARNING, NULL);
1912                 return;
1913                 }
1914
1915         /* select the first iter, so that on fail the correct info is given to user */
1916         if (gtk_tree_model_get_iter_first(store, &iter))
1917                 {
1918                 GtkTreeSelection *selection;
1919
1920                 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(rd->listview));
1921                 gtk_tree_selection_select_iter(selection, &iter);
1922                 }
1923
1924         /* now do it for real */
1925         success = TRUE;
1926         n = start_n;
1927         while (success && gtk_tree_model_get_iter_first(store, &iter))
1928                 {
1929                 gchar *dest;
1930                 gchar *base;
1931                 gchar *path;
1932
1933                 gtk_tree_model_get(store, &iter, RENAME_COLUMN_PATH, &path, -1);
1934                 base = remove_level_from_path(path);
1935
1936                 if (rd->rename_type == RENAME_TYPE_FORMATTED)
1937                         {
1938                         gchar *new_name;
1939
1940                         new_name = file_util_rename_multiple_auto_format_name(format, filename_from_path(path), n);
1941                         dest = g_strconcat(base, "/", new_name, NULL);
1942                         g_free(new_name);
1943                         }
1944                 else
1945                         {
1946                         dest = g_strdup_printf("%s/%s%0*d%s", base, front, padding, n, end);
1947                         }
1948
1949                 if (!rename_file(path, dest))
1950                         {
1951                         success = FALSE;
1952                         }
1953                 else
1954                         {
1955                         file_maint_renamed(path, dest);
1956                         }
1957
1958                 g_free(dest);
1959                 g_free(base);
1960                 g_free(path);
1961
1962                 if (success)
1963                         {
1964                         gtk_list_store_remove(GTK_LIST_STORE(store), &iter);
1965                         if (gtk_tree_model_get_iter_first(store, &iter))
1966                                 {
1967                                 GtkTreeSelection *selection;
1968
1969                                 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(rd->listview));
1970                                 gtk_tree_selection_select_iter(selection, &iter);
1971                                 }
1972                         }
1973
1974                 n++;
1975                 }
1976
1977         if (!success)
1978                 {
1979                 gchar *buf;
1980
1981                 n--;
1982                 gtk_spin_button_set_value(GTK_SPIN_BUTTON(rd->auto_spin_start), (gdouble)n);
1983
1984                 buf = g_strdup_printf(_("Failed to rename\n%s\nThe number was %d."), filename_from_path(rd->fd->source_path), n);
1985                 file_util_warning_dialog(_("Auto rename"), buf, GTK_STOCK_DIALOG_ERROR, NULL);
1986                 g_free(buf);
1987
1988                 return;
1989                 }
1990
1991         file_dialog_close(rd->fd);
1992 }
1993
1994 static void file_util_rename_multiple_cb(FileDialog *fd, gpointer data)
1995 {
1996         RenameDataMult *rd = data;
1997         gchar *base;
1998         const gchar *name;
1999
2000         if (rd->rename_type != RENAME_TYPE_MANUAL)
2001                 {
2002                 file_util_rename_multiple_auto(rd);
2003                 return;
2004                 }
2005
2006         name = gtk_entry_get_text(GTK_ENTRY(rd->rename_entry));
2007         base = remove_level_from_path(fd->source_path);
2008
2009         g_free(fd->dest_path);
2010         fd->dest_path = concat_dir_and_file(base, name);
2011         g_free(base);
2012
2013         if (strlen(name) == 0 || strcmp(fd->source_path, fd->dest_path) == 0)
2014                 {
2015                 return;
2016                 }
2017
2018         fd->type = FALSE;
2019         file_util_rename_multiple(rd);
2020 }
2021
2022 static void file_util_rename_multiple_close_cb(FileDialog *fd, gpointer data)
2023 {
2024         RenameDataMult *rd = data;
2025
2026         file_dialog_close(rd->fd);
2027 }
2028
2029 static gboolean file_util_rename_multiple_select_cb(GtkTreeSelection *selection, GtkTreeModel *store, GtkTreePath *tpath,
2030                                                     gboolean path_currently_selected, gpointer data)
2031 {
2032         RenameDataMult *rd = data;
2033         GtkTreeIter iter;
2034         const gchar *name;
2035         gchar *path = NULL;
2036
2037         if (path_currently_selected ||
2038             !gtk_tree_model_get_iter(store, &iter, tpath)) return TRUE;
2039         gtk_tree_model_get(store, &iter, RENAME_COLUMN_PATH, &path, -1);
2040
2041         g_free(rd->fd->source_path);
2042         rd->fd->source_path = path;
2043
2044         name = filename_from_path(rd->fd->source_path);
2045         gtk_label_set_text(GTK_LABEL(rd->rename_label), name);
2046         gtk_entry_set_text(GTK_ENTRY(rd->rename_entry), name);
2047
2048         image_change_path(rd->imd, rd->fd->source_path, 0.0);
2049
2050         if (GTK_WIDGET_VISIBLE(rd->rename_box))
2051                 {
2052                 gtk_widget_grab_focus(rd->rename_entry);
2053                 gtk_editable_select_region(GTK_EDITABLE(rd->rename_entry), 0, filename_base_length(name));
2054                 }
2055
2056         return TRUE;
2057 }
2058
2059 static void file_util_rename_multiple_preview_update(RenameDataMult *rd)
2060 {
2061         GtkTreeModel *store;
2062         GtkTreeIter iter;
2063         const gchar *front;
2064         const gchar *end;
2065         const gchar *format;
2066         gint valid;
2067         gint start_n;
2068         gint padding;
2069         gint n;
2070
2071         front = gtk_entry_get_text(GTK_ENTRY(rd->auto_entry_front));
2072         end = gtk_entry_get_text(GTK_ENTRY(rd->auto_entry_end));
2073         padding = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(rd->auto_spin_pad));
2074
2075         format = gtk_entry_get_text(GTK_ENTRY(rd->format_entry));
2076
2077         if (rd->rename_type == RENAME_TYPE_FORMATTED)
2078                 {
2079                 start_n = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(rd->format_spin));
2080                 }
2081         else
2082                 {
2083                 start_n = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(rd->auto_spin_start));
2084                 }
2085
2086         store = gtk_tree_view_get_model(GTK_TREE_VIEW(rd->listview));
2087         n = start_n;
2088         valid = gtk_tree_model_get_iter_first(store, &iter);
2089         while (valid)
2090                 {
2091                 gchar *dest;
2092
2093                 if (rd->rename_type == RENAME_TYPE_FORMATTED)
2094                         {
2095                         gchar *path;
2096         
2097                         gtk_tree_model_get(store, &iter, RENAME_COLUMN_PATH, &path, -1);
2098                         dest = file_util_rename_multiple_auto_format_name(format, filename_from_path(path), n);
2099                         g_free(path);
2100                         }
2101                 else
2102                         {
2103                         dest = g_strdup_printf("%s%0*d%s", front, padding, n, end);
2104                         }
2105                 gtk_list_store_set(GTK_LIST_STORE(store), &iter, RENAME_COLUMN_PREVIEW, dest, -1);
2106                 g_free(dest);
2107
2108                 n++;
2109                 valid = gtk_tree_model_iter_next(store, &iter);
2110                 }
2111
2112 }
2113
2114 static gboolean file_util_rename_multiple_idle_cb(gpointer data)
2115 {
2116         RenameDataMult *rd = data;
2117
2118         file_util_rename_multiple_preview_update(rd);
2119
2120         rd->update_idle_id = -1;
2121         return FALSE;
2122 }
2123
2124 static void file_util_rename_multiple_preview_order_cb(GtkTreeModel *treemodel, GtkTreePath *tpath,
2125                                                        GtkTreeIter *iter, gpointer data)
2126 {
2127         RenameDataMult *rd = data;
2128
2129         if (rd->rename_type != RENAME_TYPE_MANUAL && rd->update_idle_id == -1)
2130                 {
2131                 rd->update_idle_id = g_idle_add(file_util_rename_multiple_idle_cb, rd);
2132                 }
2133 }
2134
2135 static void file_util_rename_multiple_preview_entry_cb(GtkWidget *entry, gpointer data)
2136 {
2137         RenameDataMult *rd = data;
2138         file_util_rename_multiple_preview_update(rd);
2139 }
2140
2141 static void file_util_rename_multiple_preview_adj_cb(GtkWidget *spin, gpointer data)
2142 {
2143         RenameDataMult *rd = data;
2144         file_util_rename_multiple_preview_update(rd);
2145 }
2146
2147 static void file_util_rename_multiple_auto_change(GtkWidget *widget, gpointer data)
2148 {
2149         RenameDataMult *rd = data;
2150         GtkTreeViewColumn *column;
2151
2152         rd->rename_type = gtk_combo_box_get_active(GTK_COMBO_BOX(rd->combo_type));
2153
2154         switch (rd->rename_type)
2155                 {
2156                 case RENAME_TYPE_FORMATTED:
2157                         if (GTK_WIDGET_VISIBLE(rd->rename_box)) gtk_widget_hide(rd->rename_box);
2158                         if (GTK_WIDGET_VISIBLE(rd->auto_box)) gtk_widget_hide(rd->auto_box);
2159                         if (!GTK_WIDGET_VISIBLE(rd->format_box)) gtk_widget_show(rd->format_box);
2160                         file_util_rename_multiple_preview_update(rd);
2161                         break;
2162                 case RENAME_TYPE_AUTO:
2163                         if (GTK_WIDGET_VISIBLE(rd->format_box)) gtk_widget_hide(rd->format_box);
2164                         if (GTK_WIDGET_VISIBLE(rd->rename_box)) gtk_widget_hide(rd->rename_box);
2165                         if (!GTK_WIDGET_VISIBLE(rd->auto_box)) gtk_widget_show(rd->auto_box);
2166                         file_util_rename_multiple_preview_update(rd);
2167                         break;
2168                 case RENAME_TYPE_MANUAL:
2169                 default:
2170                         if (GTK_WIDGET_VISIBLE(rd->format_box)) gtk_widget_hide(rd->format_box);
2171                         if (GTK_WIDGET_VISIBLE(rd->auto_box)) gtk_widget_hide(rd->auto_box);
2172                         if (!GTK_WIDGET_VISIBLE(rd->rename_box)) gtk_widget_show(rd->rename_box);
2173                         break;
2174                 }
2175
2176         column = gtk_tree_view_get_column(GTK_TREE_VIEW(rd->listview), RENAME_COLUMN_PREVIEW - 1);
2177         gtk_tree_view_column_set_visible(column, (rd->rename_type != RENAME_TYPE_MANUAL));
2178 }
2179
2180 static GtkWidget *furm_simple_vlabel(GtkWidget *box, const gchar *text, gint expand)
2181 {
2182         GtkWidget *vbox;
2183         GtkWidget *label;
2184
2185         vbox = gtk_vbox_new(FALSE, 0);
2186         gtk_box_pack_start(GTK_BOX(box), vbox, expand, expand, 0);
2187         gtk_widget_show(vbox);
2188
2189         label = gtk_label_new(text);
2190         gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
2191         gtk_widget_show(label);
2192
2193         return vbox;
2194 }
2195
2196 static GtkTreeViewColumn *file_util_rename_multiple_add_column(RenameDataMult *rd, const gchar *text, gint n)
2197 {
2198         GtkTreeViewColumn *column;
2199         GtkCellRenderer *renderer;
2200
2201         column = gtk_tree_view_column_new();
2202         gtk_tree_view_column_set_title(column, text);
2203         gtk_tree_view_column_set_min_width(column, 4);
2204         gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_GROW_ONLY);
2205         renderer = gtk_cell_renderer_text_new();
2206         gtk_tree_view_column_pack_start(column, renderer, TRUE);
2207         gtk_tree_view_column_add_attribute(column, renderer, "text", n);
2208         gtk_tree_view_append_column(GTK_TREE_VIEW(rd->listview), column);
2209
2210         return column;
2211 }
2212
2213 static void file_util_rename_multiple_destroy_cb(GtkWidget *widget, gpointer data)
2214 {
2215         RenameDataMult *rd = data;
2216
2217         if (rd->update_idle_id != -1) g_source_remove(rd->update_idle_id);
2218
2219         g_free(rd);
2220 }
2221
2222 static void file_util_rename_multiple_do(GList *source_list, GtkWidget *parent)
2223 {
2224         RenameDataMult *rd;
2225         GtkWidget *pane;
2226         GtkWidget *scrolled;
2227         GtkListStore *store;
2228         GtkTreeSelection *selection;
2229         GtkTreeViewColumn *column;
2230         GtkWidget *hbox;
2231         GtkWidget *vbox;
2232         GtkWidget *box2;
2233         GtkWidget *table;
2234         GtkWidget *combo;
2235         GList *work;
2236         const gchar *name;
2237
2238         rd = g_new0(RenameDataMult, 1);
2239
2240         rd->fd = file_util_file_dlg(_("Rename - GQview"),
2241                                     "GQview", "dlg_rename", parent,
2242                                     file_util_rename_multiple_close_cb, rd);
2243         generic_dialog_add_message(GENERIC_DIALOG(rd->fd), NULL, _("Rename multiple files"), NULL);
2244         file_dialog_add_button(rd->fd, GTK_STOCK_OK, _("_Rename"), file_util_rename_multiple_cb, TRUE);
2245
2246         rd->fd->source_path = g_strdup(source_list->data);
2247         rd->fd->dest_path = NULL;
2248
2249         rd->rename_type = RENAME_TYPE_MANUAL;
2250
2251         rd->update_idle_id = -1;
2252
2253         vbox = GENERIC_DIALOG(rd->fd)->vbox;
2254
2255         pane = gtk_hpaned_new();
2256         gtk_box_pack_start(GTK_BOX(vbox), pane, TRUE, TRUE, 0);
2257         gtk_widget_show(pane);
2258         
2259         scrolled = gtk_scrolled_window_new(NULL, NULL);
2260         gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);
2261         gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW (scrolled),
2262                                        GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
2263         gtk_paned_pack1(GTK_PANED(pane), scrolled, TRUE, TRUE);
2264         gtk_widget_show(scrolled);
2265
2266         store = gtk_list_store_new(3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
2267         rd->listview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
2268         g_object_unref(store);
2269
2270         gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(rd->listview), TRUE);
2271         gtk_tree_view_set_enable_search(GTK_TREE_VIEW(rd->listview), FALSE);
2272
2273         selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(rd->listview));
2274         gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_SINGLE);
2275         gtk_tree_selection_set_select_function(selection, file_util_rename_multiple_select_cb, rd, NULL);
2276
2277         file_util_rename_multiple_add_column(rd, _("Original Name"), RENAME_COLUMN_NAME);
2278         column = file_util_rename_multiple_add_column(rd, _("Preview"), RENAME_COLUMN_PREVIEW);
2279         gtk_tree_view_column_set_visible(column, FALSE);
2280         
2281         gtk_tree_view_set_reorderable(GTK_TREE_VIEW(rd->listview), TRUE);
2282         g_signal_connect(G_OBJECT(store), "row_changed",
2283                          G_CALLBACK(file_util_rename_multiple_preview_order_cb), rd);
2284         gtk_widget_set_size_request(rd->listview, 250, 150);
2285
2286         gtk_container_add(GTK_CONTAINER(scrolled), rd->listview);
2287         gtk_widget_show(rd->listview);
2288
2289         work = source_list;
2290         while (work)
2291                 {
2292                 gchar *path = work->data;
2293                 GtkTreeIter iter;
2294
2295                 gtk_list_store_append(store, &iter);
2296                 gtk_list_store_set(store, &iter, RENAME_COLUMN_PATH, path, RENAME_COLUMN_NAME, filename_from_path(path), -1);
2297
2298                 work = work->next;
2299                 }
2300
2301         path_list_free(source_list);
2302
2303         rd->imd = image_new(TRUE);
2304         gtk_widget_set_size_request(rd->imd->widget, DIALOG_DEF_IMAGE_DIM_X, DIALOG_DEF_IMAGE_DIM_Y);
2305         gtk_paned_pack2(GTK_PANED(pane), rd->imd->widget, FALSE, TRUE);
2306         gtk_widget_show(rd->imd->widget);
2307
2308         hbox = gtk_hbox_new(FALSE, 0);
2309         gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
2310         gtk_widget_show(hbox);
2311
2312         rd->combo_type = gtk_combo_box_new_text();
2313
2314         gtk_combo_box_append_text(GTK_COMBO_BOX(rd->combo_type), _("Manual rename"));
2315         gtk_combo_box_append_text(GTK_COMBO_BOX(rd->combo_type), _("Formatted rename"));
2316         gtk_combo_box_append_text(GTK_COMBO_BOX(rd->combo_type), _("Auto rename"));
2317
2318         gtk_combo_box_set_active(GTK_COMBO_BOX(rd->combo_type), rd->rename_type);
2319
2320         g_signal_connect(G_OBJECT(rd->combo_type), "changed",
2321                          G_CALLBACK(file_util_rename_multiple_auto_change), rd);
2322         gtk_box_pack_end(GTK_BOX(hbox), rd->combo_type, FALSE, FALSE, 0);
2323         gtk_widget_show(rd->combo_type);
2324
2325         rd->rename_box = pref_box_new(vbox, FALSE, GTK_ORIENTATION_VERTICAL, 0);
2326         table = pref_table_new(rd->rename_box, 2, 2, FALSE, FALSE);
2327
2328         pref_table_label(table, 0, 0, _("Original name:"), 1.0);
2329         rd->rename_label = pref_table_label(table, 1, 0, filename_from_path(rd->fd->source_path), 0.0);
2330
2331         pref_table_label(table, 0, 1, _("New name:"), 1.0);
2332
2333         rd->rename_entry = gtk_entry_new();
2334         gtk_table_attach(GTK_TABLE(table), rd->rename_entry, 1, 2, 1, 2, GTK_EXPAND | GTK_FILL, FALSE, 0, 0);
2335         generic_dialog_attach_default(GENERIC_DIALOG(rd->fd), rd->rename_entry);
2336         gtk_widget_grab_focus(rd->rename_entry);
2337
2338         name = filename_from_path(rd->fd->source_path);
2339         gtk_entry_set_text(GTK_ENTRY(rd->rename_entry), name);
2340         gtk_editable_select_region(GTK_EDITABLE(rd->rename_entry), 0, filename_base_length(name));
2341         gtk_widget_show(rd->rename_entry);
2342
2343         rd->auto_box = gtk_vbox_new(FALSE, PREF_PAD_GAP);
2344         gtk_box_pack_start(GTK_BOX(vbox), rd->auto_box, FALSE, FALSE, 0);
2345         /* do not show it here */
2346
2347         hbox = pref_box_new(rd->auto_box, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_GAP);
2348
2349         box2 = furm_simple_vlabel(hbox, _("Begin text"), TRUE);
2350
2351         combo = history_combo_new(&rd->auto_entry_front, "", "numerical_rename_prefix", -1);
2352         g_signal_connect(G_OBJECT(rd->auto_entry_front), "changed",
2353                          G_CALLBACK(file_util_rename_multiple_preview_entry_cb), rd);
2354         gtk_box_pack_start(GTK_BOX(box2), combo, TRUE, TRUE, 0);
2355         gtk_widget_show(combo);
2356         
2357         box2 = furm_simple_vlabel(hbox, _("Start #"), FALSE);
2358
2359         rd->auto_spin_start = pref_spin_new(box2, NULL, NULL,
2360                                             1.0, 1000000.0, 1.0, 0, 0.0,
2361                                             G_CALLBACK(file_util_rename_multiple_preview_adj_cb), rd);
2362
2363         box2 = furm_simple_vlabel(hbox, _("End text"), TRUE);
2364
2365         combo = history_combo_new(&rd->auto_entry_end, "", "numerical_rename_suffix", -1);
2366         g_signal_connect(G_OBJECT(rd->auto_entry_end), "changed",
2367                          G_CALLBACK(file_util_rename_multiple_preview_entry_cb), rd);
2368         gtk_box_pack_start(GTK_BOX(box2), combo, TRUE, TRUE, 0);
2369         gtk_widget_show(combo);
2370
2371         rd->auto_spin_pad = pref_spin_new(rd->auto_box, _("Padding:"), NULL,
2372                                           1.0, 8.0, 1.0, 0, 1.0,
2373                                           G_CALLBACK(file_util_rename_multiple_preview_adj_cb), rd);
2374
2375         rd->format_box = gtk_vbox_new(FALSE, PREF_PAD_GAP);
2376         gtk_box_pack_start(GTK_BOX(vbox), rd->format_box, FALSE, FALSE, 0);
2377         /* do not show it here */
2378
2379         hbox = pref_box_new(rd->format_box, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_GAP);
2380
2381         box2 = furm_simple_vlabel(hbox, _("Format (* = original name, ## = numbers)"), TRUE);
2382
2383         combo = history_combo_new(&rd->format_entry, "", "auto_rename_format", -1);
2384         g_signal_connect(G_OBJECT(rd->format_entry), "changed",
2385                          G_CALLBACK(file_util_rename_multiple_preview_entry_cb), rd);
2386         gtk_box_pack_start(GTK_BOX(box2), combo, TRUE, TRUE, 0);
2387         gtk_widget_show(combo);
2388         
2389         box2 = furm_simple_vlabel(hbox, _("Start #"), FALSE);
2390
2391         rd->format_spin = pref_spin_new(box2, NULL, NULL,
2392                                         1.0, 1000000.0, 1.0, 0, 0.0,
2393                                         G_CALLBACK(file_util_rename_multiple_preview_adj_cb), rd);
2394
2395         image_change_path(rd->imd, rd->fd->source_path, 0.0);
2396
2397         g_signal_connect(G_OBJECT(GENERIC_DIALOG(rd->fd)->dialog), "destroy",
2398                          G_CALLBACK(file_util_rename_multiple_destroy_cb), rd);
2399
2400         gtk_widget_show(GENERIC_DIALOG(rd->fd)->dialog);
2401 }
2402
2403 /*
2404  * rename single file
2405  */
2406
2407 static void file_util_rename_single(FileDataSingle *fds);
2408
2409 static void file_util_rename_single_ok_cb(GenericDialog *gd, gpointer data)
2410 {
2411         FileDataSingle *fds = data;
2412         fds->confirmed = TRUE;
2413         file_util_rename_single(fds);
2414 }
2415
2416 static void file_util_rename_single_cancel_cb(GenericDialog *gd, gpointer data)
2417 {
2418         FileDataSingle *fds = data;
2419         file_data_single_free(fds);
2420 }
2421
2422 static void file_util_rename_single(FileDataSingle *fds)
2423 {
2424         if (isfile(fds->dest) && !fds->confirmed)
2425                 {
2426                 GenericDialog *gd;
2427
2428                 gd = file_util_gen_dlg(_("Overwrite file"), "GQview", "dlg_confirm",
2429                                         NULL, TRUE,
2430                                         file_util_rename_single_cancel_cb, fds);
2431
2432                 generic_dialog_add_message(gd, GTK_STOCK_DIALOG_QUESTION,
2433                                            _("Overwrite file?"),
2434                                            _("Replace existing file by renaming new file."));
2435                 pref_spacer(gd->vbox, 0);
2436
2437                 generic_dialog_add_button(gd, GTK_STOCK_OK, _("_Overwrite"), file_util_rename_single_ok_cb, TRUE);
2438                 generic_dialog_add_image(gd, fds->dest, _("Existing file"), fds->source, _("New file"), TRUE);
2439
2440                 gtk_widget_show(gd->dialog);
2441
2442                 return;
2443                 }
2444         else
2445                 {
2446                 if (!rename_file(fds->source, fds->dest))
2447                         {
2448                         gchar *text = g_strdup_printf(_("Unable to rename file:\n%s\nto:\n%s"), filename_from_path(fds->source), filename_from_path(fds->dest));
2449                         file_util_warning_dialog(_("Error renaming file"), text, GTK_STOCK_DIALOG_ERROR, NULL);
2450                         g_free(text);
2451                         }
2452                 else
2453                         {
2454                         file_maint_renamed(fds->source, fds->dest);
2455                         }
2456                 }
2457         file_data_single_free(fds);
2458 }
2459
2460 static void file_util_rename_single_cb(FileDialog *fd, gpointer data)
2461 {
2462         const gchar *name;
2463         gchar *path;
2464
2465         name = gtk_entry_get_text(GTK_ENTRY(fd->entry));
2466         path = concat_dir_and_file(fd->dest_path, name);
2467
2468         if (strlen(name) == 0 || strcmp(fd->source_path, path) == 0)
2469                 {
2470                 g_free(path);
2471                 return;
2472                 }
2473
2474         file_util_rename_single(file_data_single_new(fd->source_path, path, fd->type));
2475
2476         g_free(path);
2477         file_dialog_close(fd);
2478 }
2479
2480 static void file_util_rename_single_close_cb(FileDialog *fd, gpointer data)
2481 {
2482         file_dialog_close(fd);
2483 }
2484
2485 static void file_util_rename_single_do(const gchar *source_path, GtkWidget *parent)
2486 {
2487         FileDialog *fd;
2488         GtkWidget *table;
2489         const gchar *name;
2490
2491         fd = file_util_file_dlg(_("Rename - GQview"), "GQview", "dlg_rename", parent,
2492                              file_util_rename_single_close_cb, NULL);
2493
2494         generic_dialog_add_message(GENERIC_DIALOG(fd), NULL, _("Rename file"), NULL);
2495         generic_dialog_add_image(GENERIC_DIALOG(fd), source_path, NULL, NULL, NULL, FALSE);
2496
2497         file_dialog_add_button(fd, GTK_STOCK_OK, _("_Rename"), file_util_rename_single_cb, TRUE);
2498
2499         fd->source_path = g_strdup(source_path);
2500         fd->dest_path = remove_level_from_path(source_path);
2501
2502         table = pref_table_new(GENERIC_DIALOG(fd)->vbox, 2, 2, FALSE, FALSE);
2503
2504         pref_table_label(table, 0, 0, _("Original name:"), 1.0);
2505         pref_table_label(table, 1, 0, filename_from_path(fd->source_path), 0.0);
2506
2507         pref_table_label(table, 0, 1, _("New name:"), 1.0);
2508
2509         fd->entry = gtk_entry_new();
2510         gtk_table_attach(GTK_TABLE(table), fd->entry, 1, 2, 1, 2, GTK_EXPAND | GTK_FILL, FALSE, 0, 0);
2511         generic_dialog_attach_default(GENERIC_DIALOG(fd), fd->entry);
2512         gtk_widget_grab_focus(fd->entry);
2513
2514         name = filename_from_path(fd->source_path);
2515         gtk_entry_set_text(GTK_ENTRY(fd->entry), name);
2516         gtk_editable_select_region(GTK_EDITABLE(fd->entry), 0, filename_base_length(name));
2517         gtk_widget_show(fd->entry);
2518
2519         gtk_widget_show(GENERIC_DIALOG(fd)->dialog);
2520 }
2521
2522 void file_util_rename(const gchar *source_path, GList *source_list, GtkWidget *parent)
2523 {
2524         if (!source_path && !source_list) return;
2525
2526         if (source_path)
2527                 {
2528                 file_util_rename_single_do(source_path, parent);
2529                 }
2530         else if (!source_list->next)
2531                 {
2532                 file_util_rename_single_do(source_list->data, parent);
2533                 path_list_free(source_list);
2534                 }
2535         else
2536                 {
2537                 file_util_rename_multiple_do(source_list, parent);
2538                 }
2539 }
2540
2541 /*
2542  *--------------------------------------------------------------------------
2543  * Create directory routines
2544  *--------------------------------------------------------------------------
2545  */
2546
2547 static void file_util_create_dir_do(const gchar *base, const gchar *name)
2548 {
2549         gchar *path;
2550
2551         path = concat_dir_and_file(base, name);
2552
2553         if (isdir(path))
2554                 {
2555                 gchar *text = g_strdup_printf(_("The folder:\n%s\nalready exists."), name);
2556                 file_util_warning_dialog(_("Folder exists"), text, GTK_STOCK_DIALOG_INFO, NULL);
2557                 g_free(text);
2558                 }
2559         else if (isname(path))
2560                 {
2561                 gchar *text = g_strdup_printf(_("The path:\n%s\nalready exists as a file."), name);
2562                 file_util_warning_dialog(_("Could not create folder"), text, GTK_STOCK_DIALOG_INFO, NULL);
2563                 g_free(text);
2564                 }
2565         else
2566                 {
2567                 if (!mkdir_utf8(path, 0755))
2568                         {
2569                         gchar *text = g_strdup_printf(_("Unable to create folder:\n%s"), name);
2570                         file_util_warning_dialog(_("Error creating folder"), text, GTK_STOCK_DIALOG_ERROR, NULL);
2571                         g_free(text);
2572                         }
2573                 }
2574
2575         g_free(path);
2576 }
2577
2578 static void file_util_create_dir_cb(FileDialog *fd, gpointer data)
2579 {
2580         const gchar *name;
2581
2582         name = gtk_entry_get_text(GTK_ENTRY(fd->entry));
2583
2584         if (strlen(name) == 0) return;
2585
2586         if (name[0] == '/')
2587                 {
2588                 gchar *buf;
2589                 buf  = remove_level_from_path(name);
2590                 file_util_create_dir_do(buf, filename_from_path(name));
2591                 g_free(buf);
2592                 }
2593         else
2594                 {
2595                 file_util_create_dir_do(fd->dest_path, name);
2596                 }
2597
2598         file_dialog_close(fd);
2599 }
2600
2601 static void file_util_create_dir_close_cb(FileDialog *fd, gpointer data)
2602 {
2603         file_dialog_close(fd);
2604 }
2605
2606 void file_util_create_dir(const gchar *path, GtkWidget *parent)
2607 {
2608         FileDialog *fd;
2609         gchar *text;
2610
2611         if (!isdir(path)) return;
2612
2613         fd = file_util_file_dlg(_("New folder - GQview"), "GQview", "dlg_newdir", parent,
2614                              file_util_create_dir_close_cb, NULL);
2615
2616         text = g_strdup_printf(_("Create folder in:\n%s\nnamed:"), path);
2617         generic_dialog_add_message(GENERIC_DIALOG(fd), NULL, NULL, text);
2618         g_free(text);
2619
2620         file_dialog_add_button(fd, GTK_STOCK_OK, NULL, file_util_create_dir_cb, TRUE);
2621
2622         fd->dest_path = g_strdup(path);
2623
2624         fd->entry = gtk_entry_new();
2625         gtk_box_pack_start(GTK_BOX(GENERIC_DIALOG(fd)->vbox), fd->entry, FALSE, FALSE, 0);
2626         generic_dialog_attach_default(GENERIC_DIALOG(fd), fd->entry);
2627         gtk_widget_grab_focus(fd->entry);
2628         gtk_widget_show(fd->entry);
2629
2630         gtk_widget_show(GENERIC_DIALOG(fd)->dialog);
2631 }
2632
2633 gint file_util_rename_dir(const gchar *old_path, const gchar *new_path, GtkWidget *parent)
2634 {
2635         const gchar *old_name;
2636         const gchar *new_name;
2637
2638         if (!old_path || !new_path || !isdir(old_path)) return FALSE;
2639
2640         old_name = filename_from_path(old_path);
2641         new_name = filename_from_path(new_path);
2642
2643         if (isdir(new_path))
2644                 {
2645                 gchar *text = g_strdup_printf(_("The folder:\n%s\nalready exists."), new_name);
2646                 file_util_warning_dialog(_("Folder exists"), text, GTK_STOCK_DIALOG_INFO, parent);
2647                 g_free(text);
2648
2649                 return FALSE;
2650                 }
2651
2652         if (isname(new_path))
2653                 {
2654                 gchar *text = g_strdup_printf(_("The path:\n%s\nalready exists as a file."), new_name);
2655                 file_util_warning_dialog(_("Rename failed"), text, GTK_STOCK_DIALOG_INFO,parent);
2656                 g_free(text);
2657
2658                 return FALSE;
2659                 }
2660
2661         if (!rename_file(old_path, new_path))
2662                 {
2663                 gchar *text = g_strdup_printf(_("Failed to rename %s to %s."), old_name, new_name);
2664                 file_util_warning_dialog("Rename failed", text, GTK_STOCK_DIALOG_ERROR, parent);
2665                 g_free(text);
2666
2667                 return FALSE;
2668                 }
2669
2670         return TRUE;
2671 }
2672