29d0c9912fd9b5b3c2d2d85aa190c69c58765f38
[geeqie.git] / src / utilops.c
1 /*
2  * GQview image viewer
3  * (C)1999 John Ellis
4  *
5  * Author: John Ellis
6  *
7  */
8
9 #include "gqview.h"
10
11 enum {
12         DIALOG_NEW_DIR,
13         DIALOG_COPY,
14         DIALOG_MOVE,
15         DIALOG_DELETE,
16         DIALOG_RENAME
17 };
18
19 typedef struct _FileDataMult FileDataMult;
20 struct _FileDataMult
21 {
22         gint confirm_all;
23         gint confirmed;
24         gint skip;
25         GList *source_list;
26         GList *source_next;
27         gchar *dest_base;
28         gchar *source;
29         gchar *dest;
30         gint copy;
31 };
32
33 typedef struct _FileDataSingle FileDataSingle;
34 struct _FileDataSingle
35 {
36         gint confirmed;
37         gchar *source;
38         gchar *dest;
39         gint copy;
40 };
41
42 static FileDataMult *file_data_multiple_new(GList *source_list, gchar *dest, gint copy);
43 static void file_data_multiple_free(FileDataMult *fdm);
44 static void file_util_move_multiple(FileDataMult *fdm);
45 static void file_util_move_multiple_ok_cb(GtkWidget *widget, gpointer data);
46 static void file_util_move_multiple_all_cb(GtkWidget *widget, gpointer data);
47 static void file_util_move_multiple_skip_cb(GtkWidget *widget, gpointer data);
48 static void file_util_move_multiple_cancel_cb(GtkWidget *widget, gpointer data);
49 static void file_util_move_multiple(FileDataMult *fdm);
50
51 static FileDataSingle *file_data_single_new(gchar *source, gchar *dest, gint copy);
52 static void file_data_single_free(FileDataSingle *fds);
53 static void file_util_move_single_ok_cb(GtkWidget *widget, gpointer data);
54 static void file_util_move_single(FileDataSingle *fds);
55 static void file_util_move_single_cancel_cb(GtkWidget *widget, gpointer data);
56 static void file_util_move_do(FileDialog *fd);
57 static void file_util_move_check(FileDialog *fd);
58 static void file_util_move_cb(GtkWidget *widget, gpointer data);
59 static void file_util_move_enter_cb(gchar *path, gpointer data);
60 static void file_util_move_completion_sync_cb(gchar *path, gpointer data);
61 static void real_file_util_move(gchar *source_path, GList *source_list, gchar *dest_path, gint copy);
62
63 static void file_util_delete_multiple_ok_cb(GtkWidget *w, gpointer data);
64 static void file_util_delete_multiple_cancel_cb(GtkWidget *w, gpointer data);
65 static void file_util_delete_multiple(GList *source_list);
66 static void file_util_delete_ok_cb(GtkWidget *w, gpointer data);
67 static void file_util_delete_cancel_cb(GtkWidget *w, gpointer data);
68 static void file_util_delete_single(gchar *path);
69
70 static void file_util_rename_multiple_ok_cb(GtkWidget *w, gpointer data);
71 static void file_util_rename_multiple_cancel_cb(GtkWidget *w, gpointer data);
72 static void file_util_rename_multiple(FileDialog *fd);
73 static void file_util_rename_multiple_cb(GtkWidget *w, gpointer data);
74 static void file_util_rename_multiple_select_cb(GtkWidget *clist,
75                 gint row, gint column, GdkEventButton *bevent, gpointer data);
76 static void file_util_rename_multiple_do(GList *source_list);
77
78 static void file_util_rename_single_ok_cb(GtkWidget *w, gpointer data);
79 static void file_util_rename_single_cancel_cb(GtkWidget *w, gpointer data);
80 static void file_util_rename_single(FileDataSingle *fds);
81 static void file_util_rename_single_cb(GtkWidget *w, gpointer data);
82 static void file_util_rename_single_do(gchar *source_path);
83
84 static void file_util_create_dir_do(gchar *source, gchar *path);
85 static void file_util_create_dir_cb(GtkWidget *w, gpointer data);
86
87 /*
88  *--------------------------------------------------------------------------
89  * Move and Copy routines
90  *--------------------------------------------------------------------------
91  */
92
93 /*
94  * Multi file move
95  */
96
97 static FileDataMult *file_data_multiple_new(GList *source_list, gchar *dest, gint copy)
98 {
99         FileDataMult *fdm = g_new0(FileDataMult, 1);
100         fdm->confirm_all = FALSE;
101         fdm->confirmed = FALSE;
102         fdm->skip = FALSE;
103         fdm->source_list = source_list;
104         fdm->source_next = fdm->source_list;
105         fdm->dest_base = g_strdup(dest);
106         fdm->source = NULL;
107         fdm->dest = NULL;
108         fdm->copy = copy;
109         return fdm;
110 }
111
112 static void file_data_multiple_free(FileDataMult *fdm)
113 {
114         free_selected_list(fdm->source_list);
115         g_free(fdm->dest_base);
116         g_free(fdm->dest);
117         g_free(fdm);
118 }
119
120 static void file_util_move_multiple_ok_cb(GtkWidget *widget, gpointer data)
121 {
122         FileDataMult *fdm = data;
123         fdm->confirmed = TRUE;
124         file_util_move_multiple(fdm);
125 }
126
127 static void file_util_move_multiple_all_cb(GtkWidget *widget, gpointer data)
128 {
129         FileDataMult *fdm = data;
130         fdm->confirm_all = TRUE;
131         file_util_move_multiple(fdm);
132 }
133
134 static void file_util_move_multiple_skip_cb(GtkWidget *widget, gpointer data)
135 {
136         FileDataMult *fdm = data;
137         fdm->skip = TRUE;
138         file_util_move_multiple(fdm);
139 }
140
141 static void file_util_move_multiple_cancel_cb(GtkWidget *widget, gpointer data)
142 {
143         FileDataMult *fdm = data;
144         file_data_multiple_free(fdm);
145 }
146
147 static void file_util_move_multiple(FileDataMult *fdm)
148 {
149         while (fdm->dest || fdm->source_next)
150                 {
151                 if (!fdm->dest)
152                         {
153                         GList *work = fdm->source_next;
154                         fdm->source = work->data;
155                         fdm->dest = g_strconcat(fdm->dest_base, "/", filename_from_path(fdm->source), NULL);
156                         fdm->source_next = work->next;
157                         }
158
159                 if (isfile(fdm->dest) && !fdm->confirmed && !fdm->confirm_all && !fdm->skip)
160                         {
161                         ConfirmDialog *cd;
162                         gchar *text = g_strdup_printf(_("Overwrite file:\n %s\n with:\b %s"), fdm->dest, fdm->source);
163                         cd = confirm_dialog_new(_("Overwrite file"), text, file_util_move_multiple_cancel_cb, fdm);
164                         confirm_dialog_add(cd, _("Skip"), file_util_move_multiple_skip_cb);
165                         confirm_dialog_add(cd, _("Yes to all"), file_util_move_multiple_all_cb);
166                         confirm_dialog_add(cd, _("Yes"), file_util_move_multiple_ok_cb);
167                         g_free(text);
168                         return;
169                         }
170                 else
171                         {
172                         gint success = FALSE;
173                         if (fdm->skip)
174                                 {
175                                 success = TRUE;
176                                 fdm->skip = FALSE;
177                                 }
178                         else
179                                 {
180                                 if (fdm->copy)
181                                         {
182                                         success = copy_file(fdm->source, fdm->dest);
183                                         }
184                                 else
185                                         {
186                                         if (move_file(fdm->source, fdm->dest))
187                                                 {
188                                                 success = TRUE;
189                                                 file_is_gone(fdm->source, fdm->source_list);
190                                                 }
191                                         }
192                                 }
193                         if (!success)
194                                 {
195                                 ConfirmDialog *cd;
196                                 gchar *title;
197                                 gchar *text;
198                                 if (fdm->copy)
199                                         {
200                                         title = _("Error copying file");
201                                         text = g_strdup_printf(_("Unable to copy file:\n%sto:\n%s\n during multiple file copy."), fdm->source, fdm->dest);
202                                         }
203                                 else
204                                         {
205                                         title = _("Error moving file");
206                                         text = g_strdup_printf(_("Unable to move file:\n%sto:\n%s\n during multiple file move."), fdm->source, fdm->dest);
207                                         }
208                                 cd = confirm_dialog_new(title, text, file_util_move_multiple_cancel_cb, fdm);
209                                 confirm_dialog_add(cd, _("Continue"), file_util_move_multiple_skip_cb);
210                                 g_free(text);
211                                 return;
212                                 }
213                         fdm->confirmed = FALSE;
214                         g_free(fdm->dest);
215                         fdm->dest = NULL;
216                         }
217                 }
218
219         file_data_multiple_free(fdm);
220 }
221
222 /*
223  * Single file move
224  */
225
226 static FileDataSingle *file_data_single_new(gchar *source, gchar *dest, gint copy)
227 {
228         FileDataSingle *fds = g_new0(FileDataSingle, 1);
229         fds->confirmed = FALSE;
230         fds->source = g_strdup(source);
231         fds->dest = g_strdup(dest);
232         fds->copy = copy;
233         return fds;
234 }
235
236 static void file_data_single_free(FileDataSingle *fds)
237 {
238         g_free(fds->source);
239         g_free(fds->dest);
240         g_free(fds);
241 }
242
243 static void file_util_move_single_ok_cb(GtkWidget *widget, gpointer data)
244 {
245         FileDataSingle *fds = data;
246         fds->confirmed = TRUE;
247         file_util_move_single(fds);
248 }
249
250 static void file_util_move_single_cancel_cb(GtkWidget *widget, gpointer data)
251 {
252         FileDataSingle *fds = data;
253         file_data_single_free(fds);
254 }
255
256 static void file_util_move_single(FileDataSingle *fds)
257 {
258         if (isfile(fds->dest) && !fds->confirmed)
259                 {
260                 ConfirmDialog *cd;
261                 gchar *text = g_strdup_printf(_("Overwrite file:\n%s\n with:\n%s"), fds->dest, fds->source);
262                 cd = confirm_dialog_new(_("Overwrite file"), text, file_util_move_single_cancel_cb, fds);
263                 confirm_dialog_add(cd, _("Overwrite"), file_util_move_single_ok_cb);
264                 g_free(text);
265                 return;
266                 }
267         else
268                 {
269                 gint success = FALSE;
270                 if (fds->copy)
271                         {
272                         success = copy_file(fds->source, fds->dest);
273                         }
274                 else
275                         {
276                         if (move_file(fds->source, fds->dest))
277                                 {
278                                 success = TRUE;
279                                 file_is_gone(fds->source, NULL);
280                                 }
281                         }
282                 if (!success)
283                         {
284                         gchar *title;
285                         gchar *text;
286                         if (fds->copy)
287                                 {
288                                 title = _("Error copying file");
289                                 text = g_strdup_printf(_("Unable to copy file:\n%s\nto:\n%s"), fds->source, fds->dest);
290                                 }
291                         else
292                                 {
293                                 title = _("Error moving file");
294                                 text = g_strdup_printf(_("Unable to move file:\n%s\nto:\n%s"), fds->source, fds->dest);
295                                 }
296                         warning_dialog(title, text);
297                         g_free(text);
298                         }
299                 file_data_single_free(fds);
300                 }
301 }
302
303 /*
304  * file move dialog
305  */
306
307 static void file_util_move_do(FileDialog *fd)
308 {
309         tab_completion_append_to_history(fd->entry, fd->dest_path);
310         if (fd->multiple_files)
311                 {
312                 file_util_move_multiple(file_data_multiple_new(fd->source_list, fd->dest_path, fd->type));
313                 fd->source_list = NULL;
314                 }
315         else
316                 {
317                 if (isdir(fd->dest_path))
318                         {
319                         gchar *buf = g_strconcat(fd->dest_path, "/", filename_from_path(fd->source_path), NULL);
320                         g_free(fd->dest_path);
321                         fd->dest_path = buf;
322                         }
323                 file_util_move_single(file_data_single_new(fd->source_path, fd->dest_path, fd->type));
324                 }
325
326         generic_dialog_close(NULL, fd);
327 }
328
329 static void file_util_move_check(FileDialog *fd)
330 {
331         g_free(fd->dest_path);
332         fd->dest_path = remove_trailing_slash(gtk_entry_get_text(GTK_ENTRY(fd->entry)));
333
334         if (fd->multiple_files && !isdir(fd->dest_path))
335                 {
336                 if (isfile(fd->dest_path))
337                         warning_dialog(_("Invalid destination"), _("When operating with multiple files, please select\n a directory, not file."));
338                 else
339                         warning_dialog(_("Invalid directory"), _("Please select an existing directory"));
340                 return;
341                 }
342
343         file_util_move_do(fd);
344 }
345
346 static void file_util_move_cb(GtkWidget *widget, gpointer data)
347 {
348         FileDialog *fd = data;
349         file_util_move_check(fd);
350 }
351
352 static void file_util_move_enter_cb(gchar *path, gpointer data)
353 {
354         FileDialog *fd = data;
355         file_util_move_check(fd);
356 }
357
358 static void file_util_move_completion_sync_cb(gchar *path, gpointer data)
359 {
360         FileDialog *fd = data;
361         destination_widget_sync_to_entry(fd->entry);
362 }
363
364 static void real_file_util_move(gchar *source_path, GList *source_list, gchar *dest_path, gint copy)
365 {
366         FileDialog *fd;
367         gchar *path = NULL;
368         gint multiple;
369         gchar *text;
370         gchar *title;
371         gchar *op_text;
372         GtkWidget *tabcomp;
373         GtkWidget *dest;
374         gchar *last_path;
375
376         if (!source_path && !source_list) return;
377
378         if (source_path)
379                 {
380                 path = g_strdup(source_path);
381                 multiple = FALSE;
382                 }
383         else if (source_list->next)
384                 {
385                 multiple = TRUE;
386                 }
387         else
388                 {
389                 path = g_strdup(source_list->data);
390                 free_selected_list(source_list);
391                 source_list = NULL;
392                 multiple = FALSE;
393                 }
394
395         if (copy)
396                 {
397                 title = _("GQview - copy");
398                 op_text = _("Copy");
399                 if (path)
400                         text = g_strdup_printf(_("Copy file:\n%s\nto:"), path);
401                 else
402                         text = g_strdup_printf(_("Copy multiple files from:\n%s\nto:"), dest_path);
403                 }
404         else
405                 {
406                 title = _("GQview - move");
407                 op_text = _("Move");
408                 if (path)
409                         text = g_strdup_printf(_("Move file:\n%s\nto:"), path);
410                 else
411                         text = g_strdup_printf(_("Move multiple files from:\n%s\nto:"), dest_path);
412                 }
413
414         fd = generic_dialog_new(title, text, op_text, _("Cancel"),
415                 file_util_move_cb, generic_dialog_close);
416
417         g_free(text);
418
419         fd->type = copy;
420         fd->source_path = path;
421         fd->source_list = source_list;
422         fd->multiple_files = multiple;
423
424         tabcomp = tab_completion_new_with_history(&fd->entry, fd->dialog, dest_path,
425                                            "move_copy", 32, file_util_move_enter_cb, fd);
426         last_path = tab_completion_set_to_last_history(fd->entry);
427         if (last_path)
428                 {
429                 fd->dest_path = g_strdup(last_path);
430                 }
431         else
432                 {
433                 fd->dest_path = g_strdup(dest_path);
434                 }
435                                            
436 /*      tabcomp = tab_completion_new(&fd->entry, fd->dialog, fd->dest_path, file_util_move_enter_cb, fd);
437 */
438         gtk_box_pack_start(GTK_BOX(fd->vbox), tabcomp, FALSE, FALSE, 0);
439         gtk_widget_show(tabcomp);
440
441         gtk_widget_grab_focus(fd->entry);
442
443         dest = destination_widget_new(fd->dest_path, fd->entry);
444
445         tab_completion_add_tab_func(fd->entry, file_util_move_completion_sync_cb, fd);
446
447         gtk_box_pack_start(GTK_BOX(fd->vbox), dest, TRUE, TRUE, 0);
448 }
449
450 void file_util_move(gchar *source_path, GList *source_list, gchar *dest_path)
451 {
452         real_file_util_move(source_path, source_list, dest_path, FALSE);
453 }
454
455 void file_util_copy(gchar *source_path, GList *source_list, gchar *dest_path)
456 {
457         real_file_util_move(source_path, source_list, dest_path, TRUE);
458 }
459
460 /*
461  *--------------------------------------------------------------------------
462  * Delete routines
463  *--------------------------------------------------------------------------
464  */
465
466 /*
467  * delete multiple files
468  */
469
470 static void file_util_delete_multiple_ok_cb(GtkWidget *w, gpointer data)
471 {
472         GList *source_list = data;
473
474         while(source_list)
475                 {
476                 gchar *path = source_list->data;
477                 source_list = g_list_remove(source_list, path);
478                 if (unlink (path) < 0)
479                         {
480                         ConfirmDialog *cd;
481                         gchar *text;
482                         if (source_list)
483                                 {
484                                 text = g_strdup_printf(_("Unable to delete file:\n %s\n Continue multiple delete operation?"), path);
485                                 cd = confirm_dialog_new(_("Delete failed"), text, file_util_delete_multiple_cancel_cb, source_list);
486                                 confirm_dialog_add(cd, _("Continue"), file_util_delete_multiple_ok_cb);
487                                 }
488                         else
489                                 {
490                                 text = g_strdup_printf(_("Unable to delete file:\n%s"), path);
491                                 warning_dialog(_("Delete failed"), text);
492                                 }
493                         g_free(text);
494                         g_free(path);
495                         return;
496                         }
497                 else
498                         {
499                         file_is_gone(path, source_list);
500                         }
501                 g_free(path);
502                 }
503 }
504
505 static void file_util_delete_multiple_cancel_cb(GtkWidget *w, gpointer data)
506 {
507         GList *source_list = data;
508         free_selected_list(source_list);
509 }
510
511 static void file_util_delete_multiple(GList *source_list)
512 {
513         if (!confirm_delete)
514                 {
515                 file_util_delete_multiple_ok_cb(NULL, source_list);
516                 }
517         else
518                 {
519                 ConfirmDialog *cd;
520                 cd = confirm_dialog_new(_("Delete files"), _("About to delete multiple files..."), file_util_delete_multiple_cancel_cb, source_list);
521                 confirm_dialog_add(cd, _("Delete"), file_util_delete_multiple_ok_cb);
522                 }
523 }
524
525 /*
526  * delete single file
527  */
528
529 static void file_util_delete_ok_cb(GtkWidget *w, gpointer data)
530 {
531         gchar *path = data;
532
533         if (unlink (path) < 0)
534                 {
535                 gchar *text = g_strdup_printf(_("Unable to delete file:\n%s"), path);
536                 warning_dialog(_("File deletion failed"), text);
537                 g_free(text);
538                 }
539         else
540                 {
541                 file_is_gone(path, NULL);
542                 }
543
544         g_free(path);
545 }
546
547 static void file_util_delete_cancel_cb(GtkWidget *w, gpointer data)
548 {
549         gchar *path = data;
550         g_free(path);
551 }
552
553 static void file_util_delete_single(gchar *path)
554 {
555         gchar *buf = g_strdup(path);
556
557         if (!confirm_delete)
558                 {
559                 file_util_delete_ok_cb(NULL, buf);
560                 }
561         else
562                 {
563                 ConfirmDialog *cd;
564                 gchar *text = g_strdup_printf(_("About to delete the file:\n %s"), buf);
565                 cd = confirm_dialog_new(_("Delete file"), text, file_util_delete_cancel_cb, buf);
566                 confirm_dialog_add(cd, _("Delete"), file_util_delete_ok_cb);
567                 g_free(text);
568                 }
569 }
570
571 void file_util_delete(gchar *source_path, GList *source_list)
572 {
573         if (!source_path && !source_list) return;
574
575         if (source_path)
576                 {
577                 file_util_delete_single(source_path);
578                 }
579         else if (!source_list->next)
580                 {
581                 file_util_delete_single(source_list->data);
582                 free_selected_list(source_list);
583                 }
584         else
585                 {
586                 file_util_delete_multiple(source_list);
587                 }
588 }
589
590 /*
591  *--------------------------------------------------------------------------
592  * Rename routines
593  *--------------------------------------------------------------------------
594  */
595
596 /*
597  * rename multiple files
598  */
599
600 static void file_util_rename_multiple_ok_cb(GtkWidget *w, gpointer data)
601 {
602         FileDialog *fd = data;
603         if (!GTK_WIDGET_VISIBLE(fd->dialog)) gtk_widget_show(fd->dialog);
604         fd->type = TRUE;
605         file_util_rename_multiple(fd);
606 }
607
608 static void file_util_rename_multiple_cancel_cb(GtkWidget *w, gpointer data)
609 {
610         FileDialog *fd = data;
611         if (!GTK_WIDGET_VISIBLE(fd->dialog)) gtk_widget_show(fd->dialog);
612         return;
613 }
614
615 static void file_util_rename_multiple(FileDialog *fd)
616 {
617         if (isfile(fd->dest_path) && !fd->type)
618                 {
619                 ConfirmDialog *cd;
620                 gchar *text = g_strdup_printf(_("Overwrite file:\n%s\nby renaming:\n%s"), fd->dest_path, fd->source_path);
621                 cd = confirm_dialog_new(_("Overwrite file"), text, file_util_rename_multiple_cancel_cb, fd);
622                 confirm_dialog_add(cd, _("Overwrite"), file_util_rename_multiple_ok_cb);
623                 g_free(text);
624                 gtk_widget_hide(fd->dialog);
625                 return;
626                 }
627         else
628                 {
629                 if (rename (fd->source_path, fd->dest_path) < 0)
630                         {
631                         gchar *text = g_strdup_printf(_("Unable to rename file:\n%s\n to:\n%s"), filename_from_path(fd->source_path), filename_from_path(fd->dest_path));
632                         warning_dialog(_("Error renaming file"), text);
633                         g_free(text);
634                         }
635                 else
636                         {
637                         gint row;
638                         gint n;
639                         GtkWidget *clist;
640                         gchar *path;
641
642                         file_is_renamed(fd->source_path, fd->dest_path);
643
644                         clist = gtk_object_get_user_data(GTK_OBJECT(fd->entry));
645                         path = gtk_object_get_user_data(GTK_OBJECT(clist));
646                         row = gtk_clist_find_row_from_data(GTK_CLIST(clist), path);
647
648                         n = g_list_length(GTK_CLIST(clist)->row_list);
649                         if (debug) printf("r=%d n=%d\n", row, n);
650                         if (n - 1 > row)
651                                 n = row;
652                         else if (n > 1)
653                                 n = row - 1;
654                         else
655                                 n = -1;
656
657                         if (n >= 0)
658                                 {
659                                 gtk_object_set_user_data(GTK_OBJECT(clist), NULL);
660                                 gtk_clist_remove(GTK_CLIST(clist), row);
661                                 gtk_clist_select_row(GTK_CLIST(clist), n, -1);
662                                 }
663                         else
664                                 {
665                                 if (debug) printf("closed by #%d\n", n);
666                                 generic_dialog_close(NULL, fd);
667                                 }
668                         }
669                 }
670 }
671
672 static void file_util_rename_multiple_cb(GtkWidget *w, gpointer data)
673 {
674         FileDialog *fd = data;
675         gchar *base;
676         gchar *name;
677
678         name = gtk_entry_get_text(GTK_ENTRY(fd->entry));
679         base = remove_level_from_path(fd->source_path);
680         g_free(fd->dest_path);
681         fd->dest_path = g_strconcat(base, "/", name, NULL);
682         g_free(base);
683
684         if (strlen(name) == 0 || strcmp(fd->source_path, fd->dest_path) == 0)
685                 {
686                 return;
687                 }
688
689         fd->type = FALSE;
690         file_util_rename_multiple(fd);
691 }
692
693 static void file_util_rename_multiple_select_cb(GtkWidget *clist,
694                 gint row, gint column, GdkEventButton *bevent, gpointer data)
695 {
696         FileDialog *fd = data;
697         GtkWidget *label;
698         gchar *name;
699         gchar *path;
700
701         label = gtk_object_get_user_data(GTK_OBJECT(fd->dialog));
702         path = gtk_clist_get_row_data(GTK_CLIST(clist), row);
703         g_free(fd->source_path);
704         fd->source_path = g_strdup(path);
705         gtk_object_set_user_data(GTK_OBJECT(clist), path);
706         name = filename_from_path(fd->source_path);
707
708         gtk_label_set(GTK_LABEL(label), name);
709         gtk_entry_set_text(GTK_ENTRY(fd->entry), name);
710
711         gtk_widget_grab_focus(fd->entry);
712 }
713
714 static void file_util_rename_multiple_do(GList *source_list)
715 {
716         FileDialog *fd;
717         GtkWidget *scrolled;
718         GtkWidget *clist;
719         GtkWidget *label;
720         GList *work;
721
722         fd = generic_dialog_new(_("GQview - rename"), _("Rename multiple files:"), _("Rename"), _("Cancel"),
723                 file_util_rename_multiple_cb, generic_dialog_close);
724
725         fd->source_path = g_strdup(source_list->data);
726         fd->dest_path = NULL;
727
728         scrolled = gtk_scrolled_window_new(NULL, NULL);
729         gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
730                                 GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
731         gtk_box_pack_start(GTK_BOX(fd->vbox), scrolled, TRUE, TRUE, 0);
732         gtk_widget_show(scrolled);
733
734         clist=gtk_clist_new (1);
735         gtk_clist_set_column_auto_resize(GTK_CLIST(clist), 0, TRUE);
736         gtk_signal_connect (GTK_OBJECT (clist), "select_row",(GtkSignalFunc) file_util_rename_multiple_select_cb, fd);
737         gtk_widget_set_usize(clist, 250, 150);
738         gtk_container_add (GTK_CONTAINER (scrolled), clist);
739         gtk_widget_show (clist);
740
741         gtk_object_set_user_data(GTK_OBJECT(clist), source_list->data);
742
743         work = source_list;
744         while(work)
745                 {
746                 gint row;
747                 gchar *buf[2];
748                 buf[0] = filename_from_path(work->data);
749                 buf[1] = NULL;
750                 row = gtk_clist_append(GTK_CLIST(clist), buf);
751                 gtk_clist_set_row_data_full(GTK_CLIST(clist), row,
752                                 work->data, (GtkDestroyNotify) g_free);
753                 work = work->next;
754                 }
755
756         g_list_free(source_list);
757
758         label = gtk_label_new(_("Rename:"));
759         gtk_box_pack_start(GTK_BOX(fd->vbox), label, FALSE, FALSE, 0);
760         gtk_widget_show(label);
761
762         label = gtk_label_new(filename_from_path(fd->source_path));
763         gtk_box_pack_start(GTK_BOX(fd->vbox), label, FALSE, FALSE, 0);
764         gtk_widget_show(label);
765         gtk_object_set_user_data(GTK_OBJECT(fd->dialog), label);
766
767         label = gtk_label_new(_("to:"));
768         gtk_box_pack_start(GTK_BOX(fd->vbox), label, FALSE, FALSE, 0);
769         gtk_widget_show(label);
770
771         fd->entry = gtk_entry_new();
772         gtk_entry_set_text(GTK_ENTRY(fd->entry), filename_from_path(fd->source_path));
773         gtk_box_pack_start(GTK_BOX(fd->vbox), fd->entry, FALSE, FALSE, 0);
774         gtk_widget_grab_focus(fd->entry);
775         gtk_widget_show(fd->entry);
776
777         gtk_object_set_user_data(GTK_OBJECT(fd->entry), clist);
778 }
779
780 /*
781  * rename single file
782  */
783
784 static void file_util_rename_single_ok_cb(GtkWidget *w, gpointer data)
785 {
786         FileDataSingle *fds = data;
787         fds->confirmed = TRUE;
788         file_util_rename_single(fds);
789 }
790
791 static void file_util_rename_single_cancel_cb(GtkWidget *w, gpointer data)
792 {
793         FileDataSingle *fds = data;
794         file_data_single_free(fds);
795 }
796
797 static void file_util_rename_single(FileDataSingle *fds)
798 {
799         if (isfile(fds->dest) && !fds->confirmed)
800                 {
801                 ConfirmDialog *cd;
802                 gchar *text = g_strdup_printf(_("Overwrite file:\n%s\nwith:\n%s"), fds->dest,fds->source);
803                 cd = confirm_dialog_new(_("Overwrite file"), text, file_util_rename_single_cancel_cb, fds);
804                 confirm_dialog_add(cd, _("Overwrite"), file_util_rename_single_ok_cb);
805                 g_free(text);
806                 return;
807                 }
808         else
809                 {
810                 if (rename (fds->source, fds->dest) < 0)
811                         {
812                         gchar *text = g_strdup_printf(_("Unable to rename file:\n%s\nto:\n%s"), filename_from_path(fds->source), filename_from_path(fds->dest));
813                         warning_dialog(_("Error renaming file"), text);
814                         g_free(text);
815                         }
816                 else
817                         {
818                         file_is_renamed(fds->source, fds->dest);
819                         }
820                 }
821         file_data_single_free(fds);
822 }
823
824 static void file_util_rename_single_cb(GtkWidget *w, gpointer data)
825 {
826         FileDialog *fd = data;
827         gchar *name = gtk_entry_get_text(GTK_ENTRY(fd->entry));
828         gchar *buf = g_strconcat(fd->dest_path, "/", name, NULL);
829
830         if (strlen(name) == 0 || strcmp(fd->source_path, buf) == 0)
831                 {
832                 g_free(buf);
833                 return;
834                 }
835
836         g_free(fd->dest_path);
837         fd->dest_path = buf;
838
839         file_util_rename_single(file_data_single_new(fd->source_path, fd->dest_path, fd->type));
840
841         generic_dialog_close(NULL, fd);
842 }
843
844 static void file_util_rename_single_do(gchar *source_path)
845 {
846         FileDialog *fd;
847         gchar *text;
848         gchar *name = filename_from_path(source_path);
849
850         text = g_strdup_printf(_("Rename file:\n%s\nto:"), name);
851         fd = generic_dialog_new(_("GQview - rename"), text, _("Rename"), _("Cancel"),
852                 file_util_rename_single_cb, generic_dialog_close);
853         g_free(text);
854
855         fd->source_path = g_strdup(source_path);
856         fd->dest_path = remove_level_from_path(source_path);
857
858         fd->entry = gtk_entry_new();
859         gtk_entry_set_text(GTK_ENTRY(fd->entry), name);
860         gtk_box_pack_start(GTK_BOX(fd->vbox), fd->entry, FALSE, FALSE, 0);
861         gtk_widget_grab_focus(fd->entry);
862         gtk_widget_show(fd->entry);
863 }
864
865 void file_util_rename(gchar *source_path, GList *source_list)
866 {
867         if (!source_path && !source_list) return;
868
869         if (source_path)
870                 {
871                 file_util_rename_single_do(source_path);
872                 }
873         else if (!source_list->next)
874                 {
875                 file_util_rename_single_do(source_list->data);
876                 free_selected_list(source_list);
877                 }
878         else
879                 {
880                 file_util_rename_multiple_do(source_list);
881                 }
882 }
883
884 /*
885  *--------------------------------------------------------------------------
886  * Create directory routines
887  *--------------------------------------------------------------------------
888  */
889
890 static void file_util_create_dir_do(gchar *source, gchar *path)
891 {
892         if (isfile(path))
893                 {
894                 gchar *text = g_strdup_printf(_("The path:\n%s\nalready exists as a file."), filename_from_path(path));
895                 warning_dialog(_("Could not create directory"), text);
896                 g_free(text);
897                 }
898         else if (isdir(path))
899                 {
900                 gchar *text = g_strdup_printf(_("The directory:\n%s\nalready exists."), filename_from_path(path));
901                 warning_dialog(_("Directory exists"), text);
902                 g_free(text);
903                 }
904         else
905                 {
906                 if (mkdir (path, 0755) < 0)
907                         {
908                         gchar *text = g_strdup_printf(_("Unable to create directory:\n%s"), filename_from_path(path));
909                         warning_dialog(_("Error creating directory"), text);
910                         g_free(text);
911                         }
912                 else
913                         {
914                         if (strcmp(source, current_path) == 0)
915                                 {
916                                 gchar *buf = g_strdup(current_path);
917                                 filelist_change_to(buf);
918                                 g_free(buf);
919                                 }
920                         }
921                 }
922 }
923
924 static void file_util_create_dir_cb(GtkWidget *w, gpointer data)
925 {
926         FileDialog *fd = data;
927         gchar *name = gtk_entry_get_text(GTK_ENTRY(fd->entry));
928
929         if (strlen(name) == 0) return;
930
931         g_free(fd->dest_path);
932         fd->dest_path = g_strconcat(fd->source_path, "/", name, NULL);
933
934         file_util_create_dir_do(fd->source_path, fd->dest_path);
935
936         generic_dialog_close(NULL, fd);
937 }
938
939 void file_util_create_dir(gchar *path)
940 {
941         FileDialog *fd;
942         gchar *text;
943         gchar *name;
944
945         if (!isdir(path)) return;
946         name = filename_from_path(path);
947
948         text = g_strdup_printf(_("Create directory in:\n%s\nnamed:"), path);
949         fd = generic_dialog_new(_("GQview - new directory"), text, _("Create"), _("Cancel"),
950                 file_util_create_dir_cb, generic_dialog_close);
951         g_free(text);
952
953         fd->source_path = g_strdup(path);
954         fd->dest_path = NULL;
955
956         fd->entry = gtk_entry_new();
957         gtk_box_pack_start(GTK_BOX(fd->vbox), fd->entry, FALSE, FALSE, 0);
958         gtk_widget_grab_focus(fd->entry);
959         gtk_widget_show(fd->entry);
960 }
961