comparison src/utilops.c @ 112:b15d4c18168f

Fri Nov 17 19:06:19 2006 John Ellis <johne@verizon.net> * ui_fileops.[ch]: Add path_list_lstat() to obtain a path listing that does not follow symbolic links. * utilops.[ch]: Add file_util_delete_dir(), and support functions. * view_dir_list.c: Add delete to folder popup menu. * view_dir_tree.c: Add delete to folder popup menu, and set rename and delete sensitive only when parent folder is writable.
author gqview
date Sat, 18 Nov 2006 00:12:22 +0000
parents a10fc0308c12
children 53b2bfdcff69
comparison
equal deleted inserted replaced
111:3a69a7a3f461 112:b15d4c18168f
12 12
13 #include "gqview.h" 13 #include "gqview.h"
14 #include "utilops.h" 14 #include "utilops.h"
15 15
16 16
17 #include "cache.h"
17 #include "cache_maint.h" 18 #include "cache_maint.h"
18 #include "collect.h" 19 #include "collect.h"
19 #include "dupe.h" 20 #include "dupe.h"
20 #include "filelist.h" 21 #include "filelist.h"
21 #include "image.h" 22 #include "image.h"
22 #include "img-view.h" 23 #include "img-view.h"
23 #include "layout.h" 24 #include "layout.h"
24 #include "search.h" 25 #include "search.h"
26 #include "thumb_standard.h"
25 #include "ui_bookmark.h" 27 #include "ui_bookmark.h"
26 #include "ui_fileops.h" 28 #include "ui_fileops.h"
27 #include "ui_misc.h" 29 #include "ui_misc.h"
28 #include "ui_tabcomp.h" 30 #include "ui_tabcomp.h"
29 31
137 */ 139 */
138 140
139 #define DIALOG_DEF_IMAGE_DIM_X 200 141 #define DIALOG_DEF_IMAGE_DIM_X 200
140 #define DIALOG_DEF_IMAGE_DIM_Y 150 142 #define DIALOG_DEF_IMAGE_DIM_Y 150
141 143
142 static void generic_dialog_add_image(GenericDialog *gd, const gchar *path1, const gchar *header1, 144 static void generic_dialog_add_image(GenericDialog *gd, GtkWidget *box,
145 const gchar *path1, const gchar *header1,
143 const gchar *path2, const gchar *header2, 146 const gchar *path2, const gchar *header2,
144 gint show_filename) 147 gint show_filename)
145 { 148 {
146 ImageWindow *imd; 149 ImageWindow *imd;
147 GtkWidget *hbox = NULL; 150 GtkWidget *hbox = NULL;
148 GtkWidget *vbox; 151 GtkWidget *vbox;
149 GtkWidget *label = NULL; 152 GtkWidget *label = NULL;
150 153
154 if (!box) box = gd->vbox;
155
151 if (path2) 156 if (path2)
152 { 157 {
153 hbox = pref_box_new(gd->vbox, TRUE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE); 158 hbox = pref_box_new(box, TRUE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
154 } 159 }
155 160
156 /* image 1 */ 161 /* image 1 */
157 162
158 vbox = gtk_vbox_new(FALSE, PREF_PAD_GAP); 163 vbox = gtk_vbox_new(FALSE, PREF_PAD_GAP);
166 gtk_box_pack_start(GTK_BOX(hbox), sep, FALSE, FALSE, 0); 171 gtk_box_pack_start(GTK_BOX(hbox), sep, FALSE, FALSE, 0);
167 gtk_widget_show(sep); 172 gtk_widget_show(sep);
168 } 173 }
169 else 174 else
170 { 175 {
171 gtk_box_pack_start(GTK_BOX(gd->vbox), vbox, TRUE, TRUE, PREF_PAD_GAP); 176 gtk_box_pack_start(GTK_BOX(box), vbox, TRUE, TRUE, PREF_PAD_GAP);
172 } 177 }
173 gtk_widget_show(vbox); 178 gtk_widget_show(vbox);
174 179
175 if (header1) 180 if (header1)
176 { 181 {
180 pref_label_bold(head, TRUE, FALSE); 185 pref_label_bold(head, TRUE, FALSE);
181 gtk_misc_set_alignment(GTK_MISC(head), 0.0, 0.5); 186 gtk_misc_set_alignment(GTK_MISC(head), 0.0, 0.5);
182 } 187 }
183 188
184 imd = image_new(FALSE); 189 imd = image_new(FALSE);
190 g_object_set(G_OBJECT(imd->pr), "zoom_expand", FALSE, NULL);
185 gtk_widget_set_size_request(imd->widget, DIALOG_DEF_IMAGE_DIM_X, DIALOG_DEF_IMAGE_DIM_Y); 191 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); 192 gtk_box_pack_start(GTK_BOX(vbox), imd->widget, TRUE, TRUE, 0);
187 image_change_path(imd, path1, 0.0); 193 image_change_path(imd, path1, 0.0);
188 gtk_widget_show(imd->widget); 194 gtk_widget_show(imd->widget);
189 195
211 pref_label_bold(head, TRUE, FALSE); 217 pref_label_bold(head, TRUE, FALSE);
212 gtk_misc_set_alignment(GTK_MISC(head), 0.0, 0.5); 218 gtk_misc_set_alignment(GTK_MISC(head), 0.0, 0.5);
213 } 219 }
214 220
215 imd = image_new(FALSE); 221 imd = image_new(FALSE);
222 g_object_set(G_OBJECT(imd->pr), "zoom_expand", FALSE, NULL);
216 gtk_widget_set_size_request(imd->widget, DIALOG_DEF_IMAGE_DIM_X, DIALOG_DEF_IMAGE_DIM_Y); 223 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); 224 gtk_box_pack_start(GTK_BOX(vbox), imd->widget, TRUE, TRUE, 0);
218 image_change_path(imd, path2, 0.0); 225 image_change_path(imd, path2, 0.0);
219 gtk_widget_show(imd->widget); 226 gtk_widget_show(imd->widget);
220 227
507 generic_dialog_add_button(gd, GTK_STOCK_YES, _("_Overwrite"), file_util_move_multiple_ok_cb, TRUE); 514 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"), 515 fdm->yes_all_button = generic_dialog_add_button(gd, NULL, _("Overwrite _all"),
509 file_util_move_multiple_all_cb, FALSE); 516 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); 517 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); 518 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); 519 generic_dialog_add_image(gd, NULL, fdm->dest, _("Existing file"), fdm->source, _("New file"), TRUE);
513 520
514 /* rename option */ 521 /* rename option */
515 522
516 fdm->rename = FALSE; 523 fdm->rename = FALSE;
517 fdm->rename_all = FALSE; 524 fdm->rename_all = FALSE;
824 _("Overwrite file?"), 831 _("Overwrite file?"),
825 _("Replace existing file with new file.")); 832 _("Replace existing file with new file."));
826 pref_spacer(gd->vbox, 0); 833 pref_spacer(gd->vbox, 0);
827 834
828 generic_dialog_add_button(gd, GTK_STOCK_OK, _("_Overwrite"), file_util_move_single_ok_cb, TRUE); 835 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); 836 generic_dialog_add_image(gd, NULL, fds->dest, _("Existing file"), fds->source, _("New file"), TRUE);
830 837
831 /* rename option */ 838 /* rename option */
832 839
833 fds->rename = FALSE; 840 fds->rename = FALSE;
834 fds->rename_auto = FALSE; 841 fds->rename_auto = FALSE;
1476 "GQview", "dlg_confirm", parent, TRUE, 1483 "GQview", "dlg_confirm", parent, TRUE,
1477 file_util_delete_multiple_cancel_cb, source_list); 1484 file_util_delete_multiple_cancel_cb, source_list);
1478 1485
1479 generic_dialog_add_message(gd, NULL, _("Delete multiple files"), NULL); 1486 generic_dialog_add_message(gd, NULL, _("Delete multiple files"), NULL);
1480 1487
1481 generic_dialog_add_image(gd, NULL, NULL, NULL, NULL, TRUE); 1488 generic_dialog_add_image(gd, NULL, NULL, NULL, NULL, NULL, TRUE);
1482 imd = g_object_get_data(G_OBJECT(gd->dialog), "img_image"); 1489 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); 1490 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); 1491 image_set_scroll_func(imd, file_util_delete_multiple_review_scroll_cb, gd);
1485 1492
1486 hbox = pref_box_new(gd->vbox, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP); 1493 hbox = pref_box_new(gd->vbox, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
1565 1572
1566 base = remove_level_from_path(path); 1573 base = remove_level_from_path(path);
1567 pref_table_label(table, 1, 1, base, 0.0); 1574 pref_table_label(table, 1, 1, base, 0.0);
1568 g_free(base); 1575 g_free(base);
1569 1576
1570 generic_dialog_add_image(gd, path, NULL, NULL, NULL, FALSE); 1577 generic_dialog_add_image(gd, NULL, path, NULL, NULL, NULL, FALSE);
1571 1578
1572 box_append_safe_delete_status(gd); 1579 box_append_safe_delete_status(gd);
1573 1580
1574 generic_dialog_add_button(gd, GTK_STOCK_DELETE, NULL, file_util_delete_ok_cb, TRUE); 1581 generic_dialog_add_button(gd, GTK_STOCK_DELETE, NULL, file_util_delete_ok_cb, TRUE);
1575 1582
1714 _("Overwrite file?"), 1721 _("Overwrite file?"),
1715 _("Replace existing file by renaming new file.")); 1722 _("Replace existing file by renaming new file."));
1716 pref_spacer(gd->vbox, 0); 1723 pref_spacer(gd->vbox, 0);
1717 1724
1718 generic_dialog_add_button(gd, GTK_STOCK_OK, _("_Overwrite"), file_util_rename_multiple_ok_cb, TRUE); 1725 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); 1726 generic_dialog_add_image(gd, NULL,
1727 fd->dest_path, _("Existing file"),
1728 fd->source_path, _("New file"), TRUE);
1720 1729
1721 gtk_widget_hide(GENERIC_DIALOG(fd)->dialog); 1730 gtk_widget_hide(GENERIC_DIALOG(fd)->dialog);
1722 1731
1723 gtk_widget_show(gd->dialog); 1732 gtk_widget_show(gd->dialog);
1724 return; 1733 return;
2299 } 2308 }
2300 2309
2301 path_list_free(source_list); 2310 path_list_free(source_list);
2302 2311
2303 rd->imd = image_new(TRUE); 2312 rd->imd = image_new(TRUE);
2313 g_object_set(G_OBJECT(rd->imd->pr), "zoom_expand", FALSE, NULL);
2304 gtk_widget_set_size_request(rd->imd->widget, DIALOG_DEF_IMAGE_DIM_X, DIALOG_DEF_IMAGE_DIM_Y); 2314 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); 2315 gtk_paned_pack2(GTK_PANED(pane), rd->imd->widget, FALSE, TRUE);
2306 gtk_widget_show(rd->imd->widget); 2316 gtk_widget_show(rd->imd->widget);
2307 2317
2308 hbox = gtk_hbox_new(FALSE, 0); 2318 hbox = gtk_hbox_new(FALSE, 0);
2433 _("Overwrite file?"), 2443 _("Overwrite file?"),
2434 _("Replace existing file by renaming new file.")); 2444 _("Replace existing file by renaming new file."));
2435 pref_spacer(gd->vbox, 0); 2445 pref_spacer(gd->vbox, 0);
2436 2446
2437 generic_dialog_add_button(gd, GTK_STOCK_OK, _("_Overwrite"), file_util_rename_single_ok_cb, TRUE); 2447 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); 2448 generic_dialog_add_image(gd, NULL,
2449 fds->dest, _("Existing file"),
2450 fds->source, _("New file"), TRUE);
2439 2451
2440 gtk_widget_show(gd->dialog); 2452 gtk_widget_show(gd->dialog);
2441 2453
2442 return; 2454 return;
2443 } 2455 }
2490 2502
2491 fd = file_util_file_dlg(_("Rename - GQview"), "GQview", "dlg_rename", parent, 2503 fd = file_util_file_dlg(_("Rename - GQview"), "GQview", "dlg_rename", parent,
2492 file_util_rename_single_close_cb, NULL); 2504 file_util_rename_single_close_cb, NULL);
2493 2505
2494 generic_dialog_add_message(GENERIC_DIALOG(fd), NULL, _("Rename file"), NULL); 2506 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); 2507 generic_dialog_add_image(GENERIC_DIALOG(fd), NULL, source_path, NULL, NULL, NULL, FALSE);
2496 2508
2497 file_dialog_add_button(fd, GTK_STOCK_OK, _("_Rename"), file_util_rename_single_cb, TRUE); 2509 file_dialog_add_button(fd, GTK_STOCK_OK, _("_Rename"), file_util_rename_single_cb, TRUE);
2498 2510
2499 fd->source_path = g_strdup(source_path); 2511 fd->source_path = g_strdup(source_path);
2500 fd->dest_path = remove_level_from_path(source_path); 2512 fd->dest_path = remove_level_from_path(source_path);
2668 } 2680 }
2669 2681
2670 return TRUE; 2682 return TRUE;
2671 } 2683 }
2672 2684
2685 /*
2686 *--------------------------------------------------------------------------
2687 * Delete directory routines
2688 *--------------------------------------------------------------------------
2689 */
2690
2691 /* The plan is to eventually make all of utilops.c
2692 * use UtilityData and UtilityType.
2693 * And clean up the above mess someday.
2694 */
2695
2696 typedef enum {
2697 UTILITY_TYPE_NONE = 0,
2698 UTILITY_TYPE_COPY,
2699 UTILITY_TYPE_MOVE,
2700 UTILITY_TYPE_RENAME,
2701 UTILITY_TYPE_DELETE,
2702 UTILITY_TYPE_DELETE_LINK,
2703 UTILITY_TYPE_DELETE_FOLDER
2704 } UtilityType;
2705
2706 typedef struct _UtilityData UtilityData;
2707 struct _UtilityData {
2708 UtilityType type;
2709 gchar *source_path;
2710 GList *dlist;
2711 GList *flist;
2712
2713 GenericDialog *gd;
2714 };
2715
2716 #define UTILITY_LIST_MIN_WIDTH 250
2717 #define UTILITY_LIST_MIN_HEIGHT 150
2718
2719 /* thumbnail spec has a max depth of 4 (.thumb??/fail/appname/??.png) */
2720 #define UTILITY_DELETE_MAX_DEPTH 5
2721
2722
2723 static void file_util_data_free(UtilityData *ud)
2724 {
2725 if (!ud) return;
2726
2727 g_free(ud->source_path);
2728 path_list_free(ud->dlist);
2729 path_list_free(ud->flist);
2730
2731 if (ud->gd) generic_dialog_close(ud->gd);
2732
2733 g_free(ud);
2734 }
2735
2736 static GtkTreeViewColumn *file_util_dialog_add_list_column(GtkWidget *view, const gchar *text, gint n)
2737 {
2738 GtkTreeViewColumn *column;
2739 GtkCellRenderer *renderer;
2740
2741 column = gtk_tree_view_column_new();
2742 gtk_tree_view_column_set_title(column, text);
2743 gtk_tree_view_column_set_min_width(column, 4);
2744 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_GROW_ONLY);
2745 renderer = gtk_cell_renderer_text_new();
2746 gtk_tree_view_column_pack_start(column, renderer, TRUE);
2747 gtk_tree_view_column_add_attribute(column, renderer, "text", n);
2748 gtk_tree_view_append_column(GTK_TREE_VIEW(view), column);
2749
2750 return column;
2751 }
2752
2753 static GtkWidget *file_util_dialog_add_list(GtkWidget *box, GList *list, gint full_paths)
2754 {
2755 GtkWidget *scrolled;
2756 GtkWidget *view;
2757 GtkListStore *store;
2758
2759 scrolled = gtk_scrolled_window_new(NULL, NULL);
2760 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);
2761 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW (scrolled),
2762 GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
2763 gtk_box_pack_start(GTK_BOX(box), scrolled, TRUE, TRUE, 0);
2764 gtk_widget_show(scrolled);
2765
2766 store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_STRING);
2767 view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
2768 g_object_unref(store);
2769
2770 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(view), TRUE);
2771 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(view), FALSE);
2772
2773 if (full_paths)
2774 {
2775 file_util_dialog_add_list_column(view, _("Location"), 0);
2776 }
2777 else
2778 {
2779 file_util_dialog_add_list_column(view, _("Name"), 1);
2780 }
2781
2782 gtk_widget_set_size_request(view, UTILITY_LIST_MIN_WIDTH, UTILITY_LIST_MIN_HEIGHT);
2783 gtk_container_add(GTK_CONTAINER(scrolled), view);
2784 gtk_widget_show(view);
2785
2786 while (list)
2787 {
2788 gchar *path = list->data;
2789 GtkTreeIter iter;
2790
2791 gtk_list_store_append(store, &iter);
2792 gtk_list_store_set(store, &iter, 0, path,
2793 1, filename_from_path(path), -1);
2794
2795 list = list->next;
2796 }
2797
2798 return view;
2799 }
2800
2801 static gboolean file_util_delete_dir_preview_cb(GtkTreeSelection *selection, GtkTreeModel *store,
2802 GtkTreePath *tpath, gboolean path_currently_selected,
2803 gpointer data)
2804 {
2805 UtilityData *ud = data;
2806 GtkTreeIter iter;
2807 gchar *path = NULL;
2808
2809 if (path_currently_selected ||
2810 !gtk_tree_model_get_iter(store, &iter, tpath)) return TRUE;
2811
2812 gtk_tree_model_get(store, &iter, 0, &path, -1);
2813 generic_dialog_image_set(ud->gd, path);
2814 g_free(path);
2815
2816 return TRUE;
2817 }
2818
2819 static void file_util_delete_dir_cancel_cb(GenericDialog *gd, gpointer data)
2820 {
2821 UtilityData *ud = data;
2822
2823 ud->gd = NULL;
2824 file_util_data_free(ud);
2825 }
2826
2827 static gchar *file_util_delete_dir_empty_path(const gchar *path, gint real_content, gint level)
2828 {
2829 GList *dlist = NULL;
2830 GList *flist = NULL;
2831 GList *work;
2832 gchar *fail = NULL;
2833
2834 if (debug) printf("deltree into: %s\n", path);
2835
2836 level++;
2837 if (level > UTILITY_DELETE_MAX_DEPTH)
2838 {
2839 printf("folder recursion depth past %d, giving up\n", UTILITY_DELETE_MAX_DEPTH);
2840 return g_strdup(path);
2841 }
2842
2843 if (!path_list_lstat(path, &flist, &dlist)) return g_strdup(path);
2844
2845 work = dlist;
2846 while (work && !fail)
2847 {
2848 gchar *name;
2849
2850 name = work->data;
2851 work = work->next;
2852
2853 fail = file_util_delete_dir_empty_path(name, real_content, level);
2854 }
2855
2856 work = flist;
2857 while (work && !fail)
2858 {
2859 gchar *name;
2860
2861 name = work->data;
2862 work = work->next;
2863
2864 if (debug) printf("deltree child: %s\n", name);
2865
2866 if (real_content && !islink(name))
2867 {
2868 if (!file_util_unlink(name)) fail = g_strdup(name);
2869 }
2870 else
2871 {
2872 if (!unlink_file(name)) fail = g_strdup(name);
2873 }
2874 }
2875
2876 path_list_free(dlist);
2877 path_list_free(flist);
2878
2879 if (!fail && !rmdir_utf8(path))
2880 {
2881 fail = g_strdup(path);
2882 }
2883
2884 if (debug) printf("deltree done: %s\n", path);
2885
2886 return fail;
2887 }
2888
2889 static void file_util_delete_dir_ok_cb(GenericDialog *gd, gpointer data)
2890 {
2891 UtilityData *ud = data;
2892
2893 ud->gd = NULL;
2894
2895 if (ud->type == UTILITY_TYPE_DELETE_LINK)
2896 {
2897 if (!unlink_file(ud->source_path))
2898 {
2899 gchar *text;
2900
2901 text = g_strdup_printf("Unable to remove symbolic link:\n %s", ud->source_path);
2902 file_util_warning_dialog(_("Delete failed"), text,
2903 GTK_STOCK_DIALOG_ERROR, NULL);
2904 g_free(text);
2905 }
2906 }
2907 else
2908 {
2909 gchar *fail = NULL;
2910 GList *work;
2911
2912 work = ud->dlist;
2913 while (work && !fail)
2914 {
2915 gchar *path;
2916
2917 path = work->data;
2918 work = work->next;
2919
2920 fail = file_util_delete_dir_empty_path(path, FALSE, 0);
2921 }
2922
2923 work = ud->flist;
2924 while (work && !fail)
2925 {
2926 gchar *path;
2927
2928 path = work->data;
2929 work = work->next;
2930
2931 if (debug) printf("deltree unlink: %s\n", path);
2932
2933 if (islink(path))
2934 {
2935 if (!unlink_file(path)) fail = g_strdup(path);
2936 }
2937 else
2938 {
2939 if (!file_util_unlink(path)) fail = g_strdup(path);
2940 }
2941 }
2942
2943 if (!fail)
2944 {
2945 if (!rmdir_utf8(ud->source_path)) fail = g_strdup(ud->source_path);
2946 }
2947
2948 if (fail)
2949 {
2950 gchar *text;
2951
2952 text = g_strdup_printf(_("Unable to delete folder:\n\n%s"), ud->source_path);
2953 gd = file_util_warning_dialog(_("Delete failed"), text, GTK_STOCK_DIALOG_ERROR, NULL);
2954 g_free(text);
2955
2956 if (strcmp(fail, ud->source_path) != 0)
2957 {
2958 pref_spacer(gd->vbox, PREF_PAD_GROUP);
2959 text = g_strdup_printf(_("Removal of folder contents failed at this file:\n\n%s"),
2960 fail);
2961 pref_label_new(gd->vbox, text);
2962 g_free(text);
2963 }
2964
2965 g_free(fail);
2966 }
2967 }
2968
2969 file_util_data_free(ud);
2970 }
2971
2972 static GList *file_util_delete_dir_remaining_folders(GList *dlist)
2973 {
2974 GList *rlist = NULL;
2975
2976 while (dlist)
2977 {
2978 gchar *path;
2979 const gchar *name;
2980
2981 path = dlist->data;
2982 dlist = dlist->next;
2983
2984 name = filename_from_path(path);
2985 if (!name ||
2986 (strcmp(name, THUMB_FOLDER_GLOBAL) != 0 &&
2987 strcmp(name, THUMB_FOLDER_LOCAL) != 0 &&
2988 strcmp(name, GQVIEW_CACHE_LOCAL_METADATA) != 0) )
2989 {
2990 rlist = g_list_prepend(rlist, path);
2991 }
2992 }
2993
2994 return g_list_reverse(rlist);
2995 }
2996
2997 void file_util_delete_dir(const gchar *path, GtkWidget *parent)
2998 {
2999 GList *dlist = NULL;
3000 GList *flist = NULL;
3001 GList *rlist;
3002
3003 if (!isdir(path)) return;
3004
3005 if (islink(path))
3006 {
3007 UtilityData *ud;
3008 gchar *text;
3009
3010 ud = g_new0(UtilityData, 1);
3011 ud->type = UTILITY_TYPE_DELETE_LINK;
3012 ud->source_path = g_strdup(path);
3013 ud->dlist = NULL;
3014 ud->flist = NULL;
3015
3016 ud->gd = file_util_gen_dlg(_("Delete folder"), "GQview", "dlg_confirm",
3017 parent, TRUE,
3018 file_util_delete_dir_cancel_cb, ud);
3019
3020 text = g_strdup_printf(_("This will delete the symbolic link:\n\n%s\n\n"
3021 "The folder this link points to will not be deleted."),
3022 path);
3023 generic_dialog_add_message(ud->gd, GTK_STOCK_DIALOG_QUESTION,
3024 _("Delete symbolic link to folder?"),
3025 text);
3026 g_free(text);
3027
3028 generic_dialog_add_button(ud->gd, GTK_STOCK_DELETE, NULL, file_util_delete_dir_ok_cb, TRUE);
3029
3030 gtk_widget_show(ud->gd->dialog);
3031
3032 return;
3033 }
3034
3035 if (!access_file(path, W_OK | X_OK))
3036 {
3037 gchar *text;
3038
3039 text = g_strdup_printf(_("Unable to remove folder %s\n"
3040 "Permissions do not allow writing to the folder."), path);
3041 file_util_warning_dialog(_("Delete failed"), text, GTK_STOCK_DIALOG_ERROR, parent);
3042 g_free(text);
3043
3044 return;
3045 }
3046
3047 if (!path_list_lstat(path, &flist, &dlist))
3048 {
3049 gchar *text;
3050
3051 text = g_strdup_printf(_("Unable to list contents of folder %s"), path);
3052 file_util_warning_dialog(_("Delete failed"), text, GTK_STOCK_DIALOG_ERROR, parent);
3053 g_free(text);
3054
3055 return;
3056 }
3057
3058 rlist = file_util_delete_dir_remaining_folders(dlist);
3059 if (rlist)
3060 {
3061 GenericDialog *gd;
3062 GtkWidget *box;
3063 gchar *text;
3064
3065 gd = file_util_gen_dlg(_("Folder contains subfolders"), "GQview", "dlg_warning",
3066 parent, TRUE, NULL, NULL);
3067 generic_dialog_add_button(gd, GTK_STOCK_CLOSE, NULL, NULL, TRUE);
3068
3069 text = g_strdup_printf(_("Unable to delete the folder:\n\n%s\n\n"
3070 "This folder contains subfolders which must be moved before it can be deleted."),
3071 path);
3072 box = generic_dialog_add_message(gd, GTK_STOCK_DIALOG_WARNING,
3073 _("Folder contains subfolders"),
3074 text);
3075 g_free(text);
3076
3077 box = pref_group_new(box, TRUE, _("Subfolders:"), GTK_ORIENTATION_VERTICAL);
3078
3079 rlist = path_list_sort(rlist);
3080 file_util_dialog_add_list(box, rlist, FALSE);
3081
3082 gtk_widget_show(gd->dialog);
3083 }
3084 else
3085 {
3086 UtilityData *ud;
3087 GtkWidget *box;
3088 GtkWidget *view;
3089 GtkTreeSelection *selection;
3090 gchar *text;
3091
3092 ud = g_new0(UtilityData, 1);
3093 ud->type = UTILITY_TYPE_DELETE_FOLDER;
3094 ud->source_path = g_strdup(path);
3095 ud->dlist = dlist;
3096 dlist = NULL;
3097 ud->flist = path_list_sort(flist);
3098 flist = NULL;
3099
3100 ud->gd = file_util_gen_dlg(_("Delete folder"), "GQview", "dlg_confirm",
3101 parent, TRUE, file_util_delete_dir_cancel_cb, ud);
3102 generic_dialog_add_button(ud->gd, GTK_STOCK_DELETE, NULL, file_util_delete_dir_ok_cb, TRUE);
3103
3104 text = g_strdup_printf(_("This will delete the folder:\n\n%s\n\n"
3105 "The contents of this folder will also be deleted."),
3106 path);
3107 box = generic_dialog_add_message(ud->gd, GTK_STOCK_DIALOG_QUESTION,
3108 _("Delete folder?"),
3109 text);
3110 g_free(text);
3111
3112 box = pref_group_new(box, TRUE, _("Contents:"), GTK_ORIENTATION_HORIZONTAL);
3113
3114 view = file_util_dialog_add_list(box, ud->flist, FALSE);
3115 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
3116 gtk_tree_selection_set_mode(selection, GTK_SELECTION_SINGLE);
3117 gtk_tree_selection_set_select_function(selection, file_util_delete_dir_preview_cb, ud, NULL);
3118
3119 generic_dialog_add_image(ud->gd, box, NULL, NULL, NULL, NULL, FALSE);
3120
3121 box_append_safe_delete_status(ud->gd);
3122
3123 gtk_widget_show(ud->gd->dialog);
3124 }
3125
3126 g_list_free(rlist);
3127 path_list_free(dlist);
3128 path_list_free(flist);
3129 }
3130