2 * Copyright (C) 2006 John Ellis
3 * Copyright (C) 2008 - 2016 The Geeqie Team
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23 #include "cache_maint.h"
26 #include "cache-loader.h"
29 #include "pixbuf_util.h"
31 #include "thumb_standard.h"
32 #include "ui_fileops.h"
34 #include "ui_spinner.h"
35 #include "ui_tabcomp.h"
36 #include "ui_utildlg.h"
40 typedef struct _CMData CMData;
45 guint idle_id; /* event source id */
49 GtkWidget *button_stop;
50 GtkWidget *button_close;
56 #define PURGE_DIALOG_WIDTH 400
59 *-----------------------------------------------------------------------------
60 * Command line cache maintenance program functions *-----------------------------------------------------------------------------
62 static gchar *cache_maintenance_path = NULL;
63 static GtkStatusIcon *status_icon;
65 static void cache_maintenance_sim_stop_cb(gpointer UNUSED(data))
70 static void cache_maintenance_render_stop_cb(gpointer UNUSED(data))
72 gtk_status_icon_set_tooltip_text(status_icon, _("Geeqie: Creating sim data..."));
73 cache_manager_sim_remote(cache_maintenance_path, TRUE, (GDestroyNotify *)cache_maintenance_sim_stop_cb);
76 static void cache_maintenance_clean_stop_cb(gpointer UNUSED(data))
78 gtk_status_icon_set_tooltip_text(status_icon, _("Geeqie: Creating thumbs..."));
79 cache_manager_render_remote(cache_maintenance_path, TRUE, options->thumbnails.cache_into_dirs, (GDestroyNotify *)cache_maintenance_render_stop_cb);
82 static void cache_maintenance_user_cancel_cb()
87 static void cache_maintenance_status_icon_activate_cb(GtkStatusIcon *UNUSED(status), gpointer UNUSED(data))
92 menu = gtk_menu_new();
94 item = gtk_menu_item_new_with_label(_("Exit Geeqie Cache Maintenance"));
96 g_signal_connect(G_OBJECT(item), "activate", cache_maintenance_user_cancel_cb, item);
97 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
98 gtk_widget_show(item);
100 /* take ownership of menu */
101 g_object_ref_sink(G_OBJECT(menu));
103 gtk_menu_popup_at_pointer(GTK_MENU(menu), NULL);
106 void cache_maintenance(const gchar *path)
108 cache_maintenance_path = g_strdup(path);
110 status_icon = gtk_status_icon_new_from_pixbuf(pixbuf_inline(PIXBUF_INLINE_ICON));
111 gtk_status_icon_set_tooltip_text(status_icon, _("Geeqie: Cleaning thumbs..."));
112 gtk_status_icon_set_visible(status_icon, TRUE);
113 g_signal_connect(G_OBJECT(status_icon), "activate", G_CALLBACK(cache_maintenance_status_icon_activate_cb), NULL);
115 cache_maintain_home_remote(FALSE, FALSE, (GDestroyNotify *)cache_maintenance_clean_stop_cb);
119 *-------------------------------------------------------------------
121 *-------------------------------------------------------------------
124 static gchar *extension_find_dot(gchar *path)
128 if (!path) return NULL;
130 while (*path != '\0')
132 if (*path == '.') dot = path;
139 static gboolean isempty(const gchar *path)
145 pathl = path_from_utf8(path);
148 if (!dp) return FALSE;
150 while ((dir = readdir(dp)) != NULL)
152 gchar *name = dir->d_name;
154 if (!(name[0] == '.' && (name[1] == '\0' || (name[1] == '.' && name[2] == '\0'))) )
165 static void cache_maintain_home_close(CMData *cm)
167 if (cm->idle_id) g_source_remove(cm->idle_id);
168 if (cm->gd) generic_dialog_close(cm->gd);
169 filelist_free(cm->list);
170 g_list_free(cm->done_list);
174 static void cache_maintain_home_stop(CMData *cm)
178 g_source_remove(cm->idle_id);
184 gtk_entry_set_text(GTK_ENTRY(cm->entry), _("done"));
185 spinner_set_interval(cm->spinner, -1);
187 gtk_widget_set_sensitive(cm->button_stop, FALSE);
188 gtk_widget_set_sensitive(cm->button_close, TRUE);
192 static gboolean cache_maintain_home_cb(gpointer data)
198 gboolean just_done = FALSE;
199 gboolean still_have_a_file = TRUE;
201 const gchar *cache_folder;
202 gboolean filter_disable;
206 cache_folder = get_metadata_cache_dir();
210 cache_folder = get_thumbnails_cache_dir();
213 base_length = strlen(cache_folder);
217 DEBUG_1("purge chk done.");
219 cache_maintain_home_stop(cm);
225 DEBUG_1("purge chk (%d) \"%s\"", (cm->clear && !cm->metadata), fd->path);
228 * It is necessary to disable the file filter when clearing the cache,
229 * otherwise the .sim (file similarity) files are not deleted.
231 filter_disable = options->file_filter.disable;
232 options->file_filter.disable = TRUE;
234 if (g_list_find(cm->done_list, fd) == NULL)
236 cm->done_list = g_list_prepend(cm->done_list, fd);
238 if (filelist_read(fd, &list, &dlist))
243 still_have_a_file = FALSE;
248 FileData *fd_list = work->data;
249 gchar *path_buf = g_strdup(fd_list->path);
252 dot = extension_find_dot(path_buf);
254 if (dot) *dot = '\0';
255 if ((!cm->metadata && cm->clear) ||
256 (strlen(path_buf) > base_length && !isfile(path_buf + base_length)) )
259 if (!unlink_file(path_buf)) log_printf("failed to delete:%s\n", path_buf);
263 still_have_a_file = TRUE;
270 options->file_filter.disable = filter_disable;
274 cm->list = g_list_concat(dlist, cm->list);
276 if (cm->list && g_list_find(cm->done_list, cm->list->data) != NULL)
278 /* check if the dir is empty */
280 if (cm->list->data == fd && just_done)
282 if (!still_have_a_file && !dlist && cm->list->next && !rmdir_utf8(fd->path))
284 log_printf("Unable to delete dir: %s\n", fd->path);
289 /* must re-check for an empty dir */
290 if (isempty(fd->path) && cm->list->next && !rmdir_utf8(fd->path))
292 log_printf("Unable to delete dir: %s\n", fd->path);
297 cm->done_list = g_list_remove(cm->done_list, fd);
298 cm->list = g_list_remove(cm->list, fd);
302 if (cm->list && !cm->remote)
307 if (strlen(fd->path) > base_length)
309 buf = fd->path + base_length;
315 gtk_entry_set_text(GTK_ENTRY(cm->entry), buf);
321 static void cache_maintain_home_close_cb(GenericDialog *UNUSED(gd), gpointer data)
325 if (!gtk_widget_get_sensitive(cm->button_close)) return;
327 cache_maintain_home_close(cm);
330 static void cache_maintain_home_stop_cb(GenericDialog *UNUSED(gd), gpointer data)
334 cache_maintain_home_stop(cm);
337 /* sorry for complexity (cm->done_list), but need it to remove empty dirs */
338 void cache_maintain_home(gboolean metadata, gboolean clear, GtkWidget *parent)
344 const gchar *cache_folder;
349 cache_folder = get_metadata_cache_dir();
353 cache_folder = get_thumbnails_cache_dir();
356 dir_fd = file_data_new_dir(cache_folder);
357 if (!filelist_read(dir_fd, NULL, &dlist))
359 file_data_unref(dir_fd);
363 dlist = g_list_append(dlist, dir_fd);
365 cm = g_new0(CMData, 1);
367 cm->done_list = NULL;
369 cm->metadata = metadata;
374 msg = _("Removing old metadata...");
378 msg = _("Clearing cached thumbnails...");
382 msg = _("Removing old thumbnails...");
385 cm->gd = generic_dialog_new(_("Maintenance"),
389 cm->gd->cancel_cb = cache_maintain_home_close_cb;
390 cm->button_close = generic_dialog_add_button(cm->gd, GTK_STOCK_CLOSE, NULL,
391 cache_maintain_home_close_cb, FALSE);
392 gtk_widget_set_sensitive(cm->button_close, FALSE);
393 cm->button_stop = generic_dialog_add_button(cm->gd, GTK_STOCK_STOP, NULL,
394 cache_maintain_home_stop_cb, FALSE);
396 generic_dialog_add_message(cm->gd, NULL, msg, NULL, FALSE);
397 gtk_window_set_default_size(GTK_WINDOW(cm->gd->dialog), PURGE_DIALOG_WIDTH, -1);
399 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
400 gtk_box_pack_start(GTK_BOX(cm->gd->vbox), hbox, FALSE, FALSE, 5);
401 gtk_widget_show(hbox);
403 cm->entry = gtk_entry_new();
404 gtk_widget_set_can_focus(cm->entry, FALSE);
405 gtk_editable_set_editable(GTK_EDITABLE(cm->entry), FALSE);
406 gtk_box_pack_start(GTK_BOX(hbox), cm->entry, TRUE, TRUE, 0);
407 gtk_widget_show(cm->entry);
409 cm->spinner = spinner_new(NULL, SPINNER_SPEED);
410 gtk_box_pack_start(GTK_BOX(hbox), cm->spinner, FALSE, FALSE, 0);
411 gtk_widget_show(cm->spinner);
413 gtk_widget_show(cm->gd->dialog);
415 cm->idle_id = g_idle_add(cache_maintain_home_cb, cm);
419 * @brief Clears or culls cached data
420 * @param metadata TRUE - work on metadata cache, FALSE - work on thumbnail cache
421 * @param clear TRUE - clear cache, FALSE - delete orphaned cached items
422 * @param func Function called when idle loop function terminates
426 void cache_maintain_home_remote(gboolean metadata, gboolean clear, GDestroyNotify *func)
431 const gchar *cache_folder;
435 cache_folder = get_metadata_cache_dir();
439 cache_folder = get_thumbnails_cache_dir();
442 dir_fd = file_data_new_dir(cache_folder);
443 if (!filelist_read(dir_fd, NULL, &dlist))
445 file_data_unref(dir_fd);
449 dlist = g_list_append(dlist, dir_fd);
451 cm = g_new0(CMData, 1);
453 cm->done_list = NULL;
455 cm->metadata = metadata;
458 cm->idle_id = g_idle_add_full(G_PRIORITY_LOW, cache_maintain_home_cb, cm, (GDestroyNotify)func);
461 static void cache_file_move(const gchar *src, const gchar *dest)
463 if (!dest || !src || !isfile(src)) return;
465 if (!move_file(src, dest))
467 DEBUG_1("Failed to move cache file \"%s\" to \"%s\"", src, dest);
468 /* we remove it anyway - it's stale */
473 static void cache_maint_moved(FileData *fd)
477 const gchar *src = fd->change->source;
478 const gchar *dest = fd->change->dest;
480 if (!src || !dest) return;
482 base = cache_get_location(CACHE_TYPE_THUMB, dest, FALSE, &mode);
483 if (recursive_mkdir_if_not_exists(base, mode))
488 buf = cache_find_location(CACHE_TYPE_THUMB, src);
489 d = cache_get_location(CACHE_TYPE_THUMB, dest, TRUE, NULL);
490 cache_file_move(buf, d);
494 buf = cache_find_location(CACHE_TYPE_SIM, src);
495 d = cache_get_location(CACHE_TYPE_SIM, dest, TRUE, NULL);
496 cache_file_move(buf, d);
502 log_printf("Failed to create cache dir for move %s\n", base);
506 base = cache_get_location(CACHE_TYPE_METADATA, dest, FALSE, &mode);
507 if (recursive_mkdir_if_not_exists(base, mode))
512 buf = cache_find_location(CACHE_TYPE_METADATA, src);
513 d = cache_get_location(CACHE_TYPE_METADATA, dest, TRUE, NULL);
514 cache_file_move(buf, d);
520 if (options->thumbnails.enable_caching && options->thumbnails.spec_standard)
521 thumb_std_maint_moved(src, dest);
524 static void cache_file_remove(const gchar *path)
526 if (path && isfile(path) && !unlink_file(path))
528 DEBUG_1("Failed to remove cache file %s", path);
532 static void cache_maint_removed(FileData *fd)
536 buf = cache_find_location(CACHE_TYPE_THUMB, fd->path);
537 cache_file_remove(buf);
540 buf = cache_find_location(CACHE_TYPE_SIM, fd->path);
541 cache_file_remove(buf);
544 buf = cache_find_location(CACHE_TYPE_METADATA, fd->path);
545 cache_file_remove(buf);
548 if (options->thumbnails.enable_caching && options->thumbnails.spec_standard)
549 thumb_std_maint_removed(fd->path);
552 static void cache_maint_copied(FileData *fd)
558 src_cache = cache_find_location(CACHE_TYPE_METADATA, fd->change->source);
559 if (!src_cache) return;
561 dest_base = cache_get_location(CACHE_TYPE_METADATA, fd->change->dest, FALSE, &mode);
562 if (recursive_mkdir_if_not_exists(dest_base, mode))
566 path = cache_get_location(CACHE_TYPE_METADATA, fd->change->dest, TRUE, NULL);
567 if (!copy_file(src_cache, path))
569 DEBUG_1("failed to copy metadata %s to %s", src_cache, path);
578 void cache_notify_cb(FileData *fd, NotifyType type, gpointer UNUSED(data))
580 if (!(type & NOTIFY_CHANGE) || !fd->change) return;
582 DEBUG_1("Notify cache_maint: %s %04x", fd->path, type);
583 switch (fd->change->type)
585 case FILEDATA_CHANGE_MOVE:
586 case FILEDATA_CHANGE_RENAME:
587 cache_maint_moved(fd);
589 case FILEDATA_CHANGE_COPY:
590 cache_maint_copied(fd);
592 case FILEDATA_CHANGE_DELETE:
593 cache_maint_removed(fd);
595 case FILEDATA_CHANGE_UNSPECIFIED:
596 case FILEDATA_CHANGE_WRITE_METADATA:
603 *-------------------------------------------------------------------
604 * new cache maintenance utilities
605 *-------------------------------------------------------------------
608 typedef struct _CacheManager CacheManager;
611 GenericDialog *dialog;
612 GtkWidget *folder_entry;
621 typedef struct _CacheOpsData CacheOpsData;
627 GDestroyNotify *destroy_func; /* Used by the command line prog. functions */
635 GtkWidget *button_close;
636 GtkWidget *button_stop;
637 GtkWidget *button_start;
639 GtkWidget *progress_bar;
653 guint idle_id; /* event source id */
656 static void cache_manager_render_reset(CacheOpsData *cd)
658 filelist_free(cd->list);
661 filelist_free(cd->list_dir);
664 thumb_loader_free((ThumbLoader *)cd->tl);
668 static void cache_manager_render_close_cb(GenericDialog *UNUSED(fd), gpointer data)
670 CacheOpsData *cd = data;
672 if (!gtk_widget_get_sensitive(cd->button_close)) return;
674 cache_manager_render_reset(cd);
675 generic_dialog_close(cd->gd);
679 static void cache_manager_render_finish(CacheOpsData *cd)
681 cache_manager_render_reset(cd);
684 gtk_entry_set_text(GTK_ENTRY(cd->progress), _("done"));
685 spinner_set_interval(cd->spinner, -1);
687 gtk_widget_set_sensitive(cd->group, TRUE);
688 gtk_widget_set_sensitive(cd->button_start, TRUE);
689 gtk_widget_set_sensitive(cd->button_stop, FALSE);
690 gtk_widget_set_sensitive(cd->button_close, TRUE);
694 static void cache_manager_render_stop_cb(GenericDialog *UNUSED(fd), gpointer data)
696 CacheOpsData *cd = data;
698 gtk_entry_set_text(GTK_ENTRY(cd->progress), _("stopped"));
699 cache_manager_render_finish(cd);
702 static void cache_manager_render_folder(CacheOpsData *cd, FileData *dir_fd)
704 GList *list_d = NULL;
705 GList *list_f = NULL;
709 filelist_read(dir_fd, &list_f, &list_d);
713 filelist_read(dir_fd, &list_f, NULL);
716 list_f = filelist_filter(list_f, FALSE);
717 list_d = filelist_filter(list_d, TRUE);
719 cd->list = g_list_concat(list_f, cd->list);
720 cd->list_dir = g_list_concat(list_d, cd->list_dir);
723 static gboolean cache_manager_render_file(CacheOpsData *cd);
725 static void cache_manager_render_thumb_done_cb(ThumbLoader *UNUSED(tl), gpointer data)
727 CacheOpsData *cd = data;
729 thumb_loader_free((ThumbLoader *)cd->tl);
732 while (cache_manager_render_file(cd));
735 static gboolean cache_manager_render_file(CacheOpsData *cd)
743 cd->list = g_list_remove(cd->list, fd);
745 cd->tl = (ThumbLoaderStd *)thumb_loader_new(options->thumbnails.max_width, options->thumbnails.max_height);
746 thumb_loader_set_callbacks((ThumbLoader *)cd->tl,
747 cache_manager_render_thumb_done_cb,
748 cache_manager_render_thumb_done_cb,
750 thumb_loader_set_cache((ThumbLoader *)cd->tl, TRUE, cd->local, TRUE);
751 success = thumb_loader_start((ThumbLoader *)cd->tl, fd);
756 gtk_entry_set_text(GTK_ENTRY(cd->progress), fd->path);
757 cd->count_done = cd->count_done + 1;
758 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(cd->progress_bar), (gdouble)cd->count_done / cd->count_total);
763 thumb_loader_free((ThumbLoader *)cd->tl);
771 else if (cd->list_dir)
775 fd = cd->list_dir->data;
776 cd->list_dir = g_list_remove(cd->list_dir, fd);
778 cache_manager_render_folder(cd, fd);
787 gtk_entry_set_text(GTK_ENTRY(cd->progress), _("done"));
789 cache_manager_render_finish(cd);
791 if (cd->destroy_func)
793 g_idle_add((GSourceFunc)cd->destroy_func, NULL);
799 static void cache_manager_render_start_cb(GenericDialog *UNUSED(fd), gpointer data)
801 CacheOpsData *cd = data;
803 GList *list_total = NULL;
807 if (cd->list || !gtk_widget_get_sensitive(cd->button_start)) return;
810 path = remove_trailing_slash((gtk_entry_get_text(GTK_ENTRY(cd->entry))));
811 parse_out_relatives(path);
817 warning_dialog(_("Invalid folder"),
818 _("The specified folder can not be found."),
819 GTK_STOCK_DIALOG_WARNING, cd->gd->dialog);
823 log_printf("The specified folder can not be found: %s\n", path);
831 gtk_widget_set_sensitive(cd->group, FALSE);
832 gtk_widget_set_sensitive(cd->button_start, FALSE);
833 gtk_widget_set_sensitive(cd->button_stop, TRUE);
834 gtk_widget_set_sensitive(cd->button_close, FALSE);
836 spinner_set_interval(cd->spinner, SPINNER_SPEED);
838 dir_fd = file_data_new_dir(path);
839 cache_manager_render_folder(cd, dir_fd);
840 list_total = filelist_recursive(dir_fd);
841 cd->count_total = g_list_length(list_total);
842 file_data_unref(dir_fd);
843 g_list_free(list_total);
846 while (cache_manager_render_file(cd));
852 static void cache_manager_render_start_render_remote(CacheOpsData *cd, const gchar *user_path)
856 path = remove_trailing_slash(user_path);
857 parse_out_relatives(path);
861 log_printf("The specified folder can not be found: %s\n", path);
867 dir_fd = file_data_new_dir(path);
868 cache_manager_render_folder(cd, dir_fd);
869 file_data_unref(dir_fd);
870 while (cache_manager_render_file(cd));
876 static void cache_manager_render_dialog(GtkWidget *widget, const gchar *path)
883 cd = g_new0(CacheOpsData, 1);
886 cd->gd = generic_dialog_new(_("Create thumbnails"),
890 gtk_window_set_default_size(GTK_WINDOW(cd->gd->dialog), PURGE_DIALOG_WIDTH, -1);
891 cd->gd->cancel_cb = cache_manager_render_close_cb;
892 cd->button_close = generic_dialog_add_button(cd->gd, GTK_STOCK_CLOSE, NULL,
893 cache_manager_render_close_cb, FALSE);
894 cd->button_start = generic_dialog_add_button(cd->gd, GTK_STOCK_OK, _("S_tart"),
895 cache_manager_render_start_cb, FALSE);
896 cd->button_stop = generic_dialog_add_button(cd->gd, GTK_STOCK_STOP, NULL,
897 cache_manager_render_stop_cb, FALSE);
898 gtk_widget_set_sensitive(cd->button_stop, FALSE);
900 generic_dialog_add_message(cd->gd, NULL, _("Create thumbnails"), NULL, FALSE);
902 hbox = pref_box_new(cd->gd->vbox, FALSE, GTK_ORIENTATION_HORIZONTAL, 0);
903 pref_spacer(hbox, PREF_PAD_INDENT);
904 cd->group = pref_box_new(hbox, TRUE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
906 hbox = pref_box_new(cd->group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
907 pref_label_new(hbox, _("Folder:"));
909 label = tab_completion_new(&cd->entry, path, NULL, NULL, NULL, NULL);
910 tab_completion_add_select_button(cd->entry,_("Select folder") , TRUE);
911 gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0);
912 gtk_widget_show(label);
914 pref_checkbox_new_int(cd->group, _("Include subfolders"), FALSE, &cd->recurse);
915 button = pref_checkbox_new_int(cd->group, _("Store thumbnails local to source images"), FALSE, &cd->local);
916 gtk_widget_set_sensitive(button, options->thumbnails.spec_standard);
918 pref_line(cd->gd->vbox, PREF_PAD_SPACE);
919 hbox = pref_box_new(cd->gd->vbox, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
921 cd->progress = gtk_entry_new();
922 gtk_widget_set_can_focus(cd->progress, FALSE);
923 gtk_editable_set_editable(GTK_EDITABLE(cd->progress), FALSE);
924 gtk_entry_set_text(GTK_ENTRY(cd->progress), _("click start to begin"));
925 gtk_box_pack_start(GTK_BOX(hbox), cd->progress, TRUE, TRUE, 0);
926 gtk_widget_show(cd->progress);
928 cd->progress_bar = gtk_progress_bar_new();
929 gtk_box_pack_start(GTK_BOX(cd->gd->vbox), cd->progress_bar, TRUE, TRUE, 0);
930 gtk_widget_show(cd->progress_bar);
932 cd->spinner = spinner_new(NULL, -1);
933 gtk_box_pack_start(GTK_BOX(hbox), cd->spinner, FALSE, FALSE, 0);
934 gtk_widget_show(cd->spinner);
938 gtk_widget_show(cd->gd->dialog);
942 * @brief Create thumbnails
943 * @param path Path to image folder
945 * @param local Create thumbnails in same folder as images
946 * @param func Function called when idle loop function terminates
950 void cache_manager_render_remote(const gchar *path, gboolean recurse, gboolean local, GDestroyNotify *func)
954 cd = g_new0(CacheOpsData, 1);
955 cd->recurse = recurse;
958 cd->destroy_func = func;
960 cache_manager_render_start_render_remote(cd, path);
963 static void cache_manager_standard_clean_close_cb(GenericDialog *UNUSED(gd), gpointer data)
965 CacheOpsData *cd = data;
967 if (!gtk_widget_get_sensitive(cd->button_close)) return;
969 generic_dialog_close(cd->gd);
971 thumb_loader_std_thumb_file_validate_cancel(cd->tl);
972 filelist_free(cd->list);
976 static void cache_manager_standard_clean_done(CacheOpsData *cd)
980 gtk_widget_set_sensitive(cd->button_stop, FALSE);
981 gtk_widget_set_sensitive(cd->button_close, TRUE);
983 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(cd->progress), 1.0);
984 gtk_progress_bar_set_text(GTK_PROGRESS_BAR(cd->progress), _("done"));
988 g_source_remove(cd->idle_id);
992 thumb_loader_std_thumb_file_validate_cancel(cd->tl);
995 filelist_free(cd->list);
999 static void cache_manager_standard_clean_stop_cb(GenericDialog *UNUSED(gd), gpointer data)
1001 CacheOpsData *cd = data;
1003 cache_manager_standard_clean_done(cd);
1006 static gint cache_manager_standard_clean_clear_cb(gpointer data)
1008 CacheOpsData *cd = data;
1014 next_fd = cd->list->data;
1015 cd->list = g_list_remove(cd->list, next_fd);
1017 DEBUG_1("thumb removed: %s", next_fd->path);
1019 unlink_file(next_fd->path);
1020 file_data_unref(next_fd);
1025 if (cd->count_total != 0)
1027 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(cd->progress),
1028 (gdouble)cd->count_done / cd->count_total);
1036 cache_manager_standard_clean_done(cd);
1040 static void cache_manager_standard_clean_valid_cb(const gchar *path, gboolean valid, gpointer data)
1042 CacheOpsData *cd = data;
1048 DEBUG_1("thumb cleaned: %s", path);
1055 if (cd->count_total != 0)
1057 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(cd->progress),
1058 (gdouble)cd->count_done / cd->count_total);
1068 next_fd = cd->list->data;
1069 cd->list = g_list_remove(cd->list, next_fd);
1071 cd->tl = thumb_loader_std_thumb_file_validate(next_fd->path, cd->days,
1072 cache_manager_standard_clean_valid_cb, cd);
1073 file_data_unref(next_fd);
1077 cache_manager_standard_clean_done(cd);
1081 static void cache_manager_standard_clean_start(GenericDialog *UNUSED(gd), gpointer data)
1083 CacheOpsData *cd = data;
1090 if (cd->list || !gtk_widget_get_sensitive(cd->button_start)) return;
1092 gtk_widget_set_sensitive(cd->button_start, FALSE);
1093 gtk_widget_set_sensitive(cd->button_stop, TRUE);
1094 gtk_widget_set_sensitive(cd->button_close, FALSE);
1096 gtk_progress_bar_set_text(GTK_PROGRESS_BAR(cd->progress), _("running..."));
1099 path = g_build_filename(get_thumbnails_standard_cache_dir(), THUMB_FOLDER_NORMAL, NULL);
1100 dir_fd = file_data_new_dir(path);
1101 filelist_read(dir_fd, &list, NULL);
1103 file_data_unref(dir_fd);
1106 path = g_build_filename(get_thumbnails_standard_cache_dir(), THUMB_FOLDER_LARGE, NULL);
1107 dir_fd = file_data_new_dir(path);
1108 filelist_read(dir_fd, &list, NULL);
1109 cd->list = g_list_concat(cd->list, list);
1110 file_data_unref(dir_fd);
1113 path = g_build_filename(get_thumbnails_standard_cache_dir(), THUMB_FOLDER_FAIL, NULL);
1114 dir_fd = file_data_new_dir(path);
1115 filelist_read(dir_fd, &list, NULL);
1116 cd->list = g_list_concat(cd->list, list);
1117 file_data_unref(dir_fd);
1120 cd->count_total = g_list_length(cd->list);
1123 /* start iterating */
1126 cd->idle_id = g_idle_add(cache_manager_standard_clean_clear_cb, cd);
1130 cache_manager_standard_clean_valid_cb(NULL, TRUE, cd);
1134 static void cache_manager_standard_clean_start_cb(GenericDialog *gd, gpointer data)
1136 cache_manager_standard_clean_start(gd, data);
1139 static void cache_manager_standard_process(GtkWidget *widget, gboolean clear)
1142 const gchar *stock_id;
1145 cd = g_new0(CacheOpsData, 1);
1151 stock_id = GTK_STOCK_DELETE;
1152 msg = _("Clearing thumbnails...");
1156 stock_id = GTK_STOCK_CLEAR;
1157 msg = _("Removing old thumbnails...");
1160 cd->gd = generic_dialog_new(_("Maintenance"),
1161 "standard_maintenance",
1164 cd->gd->cancel_cb = cache_manager_standard_clean_close_cb;
1165 cd->button_close = generic_dialog_add_button(cd->gd, GTK_STOCK_CLOSE, NULL,
1166 cache_manager_standard_clean_close_cb, FALSE);
1167 cd->button_start = generic_dialog_add_button(cd->gd, GTK_STOCK_OK, _("S_tart"),
1168 cache_manager_standard_clean_start_cb, FALSE);
1169 cd->button_stop = generic_dialog_add_button(cd->gd, GTK_STOCK_STOP, NULL,
1170 cache_manager_standard_clean_stop_cb, FALSE);
1171 gtk_widget_set_sensitive(cd->button_stop, FALSE);
1173 generic_dialog_add_message(cd->gd, stock_id, msg, NULL, FALSE);
1175 cd->progress = gtk_progress_bar_new();
1176 gtk_progress_bar_set_text(GTK_PROGRESS_BAR(cd->progress), _("click start to begin"));
1177 gtk_progress_bar_set_show_text(GTK_PROGRESS_BAR(cd->progress), TRUE);
1178 gtk_box_pack_start(GTK_BOX(cd->gd->vbox), cd->progress, FALSE, FALSE, 0);
1179 gtk_widget_show(cd->progress);
1185 gtk_widget_show(cd->gd->dialog);
1188 void cache_manager_standard_process_remote(gboolean clear)
1192 cd = g_new0(CacheOpsData, 1);
1199 cache_manager_standard_clean_start(NULL, cd);
1202 static void cache_manager_standard_clean_cb(GtkWidget *widget, gpointer UNUSED(data))
1204 cache_manager_standard_process(widget, FALSE);
1207 static void cache_manager_standard_clear_cb(GtkWidget *widget, gpointer UNUSED(data))
1209 cache_manager_standard_process(widget, TRUE);
1213 static void cache_manager_main_clean_cb(GtkWidget *widget, gpointer UNUSED(data))
1215 cache_maintain_home(FALSE, FALSE, widget);
1219 static void dummy_cancel_cb(GenericDialog *UNUSED(gd), gpointer UNUSED(data))
1221 /* no op, only so cancel button appears */
1224 static void cache_manager_main_clear_ok_cb(GenericDialog *UNUSED(gd), gpointer UNUSED(data))
1226 cache_maintain_home(FALSE, TRUE, NULL);
1229 void cache_manager_main_clear_confirm(GtkWidget *parent)
1233 gd = generic_dialog_new(_("Clear cache"),
1234 "clear_cache", parent, TRUE,
1235 dummy_cancel_cb, NULL);
1236 generic_dialog_add_message(gd, GTK_STOCK_DIALOG_QUESTION, _("Clear cache"),
1237 _("This will remove all thumbnails and sim. files\nthat have been saved to disk, continue?"), TRUE);
1238 generic_dialog_add_button(gd, GTK_STOCK_OK, NULL, cache_manager_main_clear_ok_cb, TRUE);
1240 gtk_widget_show(gd->dialog);
1243 static void cache_manager_main_clear_cb(GtkWidget *widget, gpointer UNUSED(data))
1245 cache_manager_main_clear_confirm(widget);
1248 static void cache_manager_render_cb(GtkWidget *widget, gpointer UNUSED(data))
1250 const gchar *path = layout_get_path(NULL);
1252 if (!path || !*path) path = homedir();
1253 cache_manager_render_dialog(widget, path);
1256 static void cache_manager_metadata_clean_cb(GtkWidget *widget, gpointer UNUSED(data))
1258 cache_maintain_home(TRUE, FALSE, widget);
1262 static CacheManager *cache_manager = NULL;
1264 static void cache_manager_close_cb(GenericDialog *gd, gpointer UNUSED(data))
1266 generic_dialog_close(gd);
1268 g_free(cache_manager);
1269 cache_manager = NULL;
1272 static void cache_manager_help_cb(GenericDialog *UNUSED(gd), gpointer UNUSED(data))
1274 help_window_show("GuideReferenceManagement.html");
1277 static GtkWidget *cache_manager_location_label(GtkWidget *group, const gchar *subdir)
1282 buf = g_strdup_printf(_("Location: %s"), subdir);
1283 label = pref_label_new(group, buf);
1285 gtk_label_set_xalign(GTK_LABEL(label), 0.0);
1286 gtk_label_set_yalign(GTK_LABEL(label), 0.5);
1291 static gboolean cache_manager_sim_file(CacheOpsData *cd);
1293 static void cache_manager_sim_reset(CacheOpsData *cd)
1295 filelist_free(cd->list);
1298 filelist_free(cd->list_dir);
1299 cd->list_dir = NULL;
1301 cache_loader_free((CacheLoader *)cd->cl);
1305 static void cache_manager_sim_close_cb(GenericDialog *UNUSED(fd), gpointer data)
1307 CacheOpsData *cd = data;
1309 if (!gtk_widget_get_sensitive(cd->button_close)) return;
1311 cache_manager_sim_reset(cd);
1312 generic_dialog_close(cd->gd);
1316 static void cache_manager_sim_finish(CacheOpsData *cd)
1318 cache_manager_sim_reset(cd);
1321 spinner_set_interval(cd->spinner, -1);
1323 gtk_widget_set_sensitive(cd->group, TRUE);
1324 gtk_widget_set_sensitive(cd->button_start, TRUE);
1325 gtk_widget_set_sensitive(cd->button_stop, FALSE);
1326 gtk_widget_set_sensitive(cd->button_close, TRUE);
1330 static void cache_manager_sim_stop_cb(GenericDialog *UNUSED(fd), gpointer data)
1332 CacheOpsData *cd = data;
1334 gtk_entry_set_text(GTK_ENTRY(cd->progress), _("stopped"));
1335 cache_manager_sim_finish(cd);
1338 static void cache_manager_sim_folder(CacheOpsData *cd, FileData *dir_fd)
1340 GList *list_d = NULL;
1341 GList *list_f = NULL;
1345 filelist_read(dir_fd, &list_f, &list_d);
1349 filelist_read(dir_fd, &list_f, NULL);
1352 list_f = filelist_filter(list_f, FALSE);
1353 list_d = filelist_filter(list_d, TRUE);
1355 cd->list = g_list_concat(list_f, cd->list);
1356 cd->list_dir = g_list_concat(list_d, cd->list_dir);
1359 static void cache_manager_sim_file_done_cb(CacheLoader *UNUSED(cl), gint UNUSED(error), gpointer data)
1361 CacheOpsData *cd = data;
1363 cache_loader_free((CacheLoader *)cd->cl);
1366 while (cache_manager_sim_file(cd));
1369 static void cache_manager_sim_start_sim_remote(CacheOpsData *cd, const gchar *user_path)
1373 path = remove_trailing_slash(user_path);
1374 parse_out_relatives(path);
1378 log_printf("The specified folder can not be found: %s\n", path);
1384 dir_fd = file_data_new_dir(path);
1385 cache_manager_sim_folder(cd, dir_fd);
1386 file_data_unref(dir_fd);
1387 while (cache_manager_sim_file(cd));
1394 * @brief Generate .sim files
1395 * @param path Path to image folder
1397 * @param func Function called when idle loop function terminates
1401 void cache_manager_sim_remote(const gchar *path, gboolean recurse, GDestroyNotify *func)
1405 cd = g_new0(CacheOpsData, 1);
1406 cd->recurse = recurse;
1408 cd->destroy_func = func;
1410 cache_manager_sim_start_sim_remote(cd, path);
1413 static gboolean cache_manager_sim_file(CacheOpsData *cd)
1415 CacheDataType load_mask;
1420 fd = cd->list->data;
1421 cd->list = g_list_remove(cd->list, fd);
1423 load_mask = CACHE_LOADER_DIMENSIONS | CACHE_LOADER_DATE | CACHE_LOADER_MD5SUM | CACHE_LOADER_SIMILARITY;
1424 cd->cl = (CacheLoader *)cache_loader_new(fd, load_mask, (cache_manager_sim_file_done_cb), cd);
1428 gtk_entry_set_text(GTK_ENTRY(cd->progress), fd->path);
1431 file_data_unref(fd);
1432 cd->count_done = cd->count_done + 1;
1435 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(cd->progress_bar), (gdouble)cd->count_done / cd->count_total);
1440 else if (cd->list_dir)
1444 fd = cd->list_dir->data;
1445 cd->list_dir = g_list_remove(cd->list_dir, fd);
1447 cache_manager_sim_folder((CacheOpsData *)cd, fd);
1448 file_data_unref(fd);
1455 gtk_entry_set_text(GTK_ENTRY(cd->progress), _("done"));
1458 cache_manager_sim_finish((CacheOpsData *)cd);
1460 if (cd->destroy_func)
1462 g_idle_add((GSourceFunc)cd->destroy_func, NULL);
1468 static void cache_manager_sim_start_cb(GenericDialog *UNUSED(fd), gpointer data)
1470 CacheOpsData *cd = data;
1472 GList *list_total = NULL;
1476 if (cd->list || !gtk_widget_get_sensitive(cd->button_start)) return;
1479 path = remove_trailing_slash((gtk_entry_get_text(GTK_ENTRY(cd->entry))));
1480 parse_out_relatives(path);
1486 warning_dialog(_("Invalid folder"),
1487 _("The specified folder can not be found."),
1488 GTK_STOCK_DIALOG_WARNING, cd->gd->dialog);
1492 log_printf("The specified folder can not be found: %s\n", path);
1500 gtk_widget_set_sensitive(cd->group, FALSE);
1501 gtk_widget_set_sensitive(cd->button_start, FALSE);
1502 gtk_widget_set_sensitive(cd->button_stop, TRUE);
1503 gtk_widget_set_sensitive(cd->button_close, FALSE);
1505 spinner_set_interval(cd->spinner, SPINNER_SPEED);
1507 dir_fd = file_data_new_dir(path);
1508 cache_manager_sim_folder(cd, dir_fd);
1509 list_total = filelist_recursive(dir_fd);
1510 cd->count_total = g_list_length(list_total);
1511 file_data_unref(dir_fd);
1512 g_list_free(list_total);
1515 while (cache_manager_sim_file((CacheOpsData *)cd));
1521 static void cache_manager_sim_load_dialog(GtkWidget *widget, const gchar *path)
1527 cd = g_new0(CacheOpsData, 1);
1531 cd->gd = generic_dialog_new(_("Create sim. files"), "create_sim_files", widget, FALSE, NULL, cd);
1532 gtk_window_set_default_size(GTK_WINDOW(cd->gd->dialog), PURGE_DIALOG_WIDTH, -1);
1533 cd->gd->cancel_cb = cache_manager_sim_close_cb;
1534 cd->button_close = generic_dialog_add_button(cd->gd, GTK_STOCK_CLOSE, NULL,
1535 cache_manager_sim_close_cb, FALSE);
1536 cd->button_start = generic_dialog_add_button(cd->gd, GTK_STOCK_OK, _("S_tart"),
1537 cache_manager_sim_start_cb, FALSE);
1538 cd->button_stop = generic_dialog_add_button(cd->gd, GTK_STOCK_STOP, NULL,
1539 cache_manager_sim_stop_cb, FALSE);
1540 gtk_widget_set_sensitive(cd->button_stop, FALSE);
1542 generic_dialog_add_message(cd->gd, NULL, _("Create sim. files recursively"), NULL, FALSE);
1544 hbox = pref_box_new(cd->gd->vbox, FALSE, GTK_ORIENTATION_HORIZONTAL, 0);
1545 pref_spacer(hbox, PREF_PAD_INDENT);
1546 cd->group = pref_box_new(hbox, TRUE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
1548 hbox = pref_box_new(cd->group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
1549 pref_label_new(hbox, _("Folder:"));
1551 label = tab_completion_new(&cd->entry, path, NULL, NULL, NULL, NULL);
1552 tab_completion_add_select_button(cd->entry,_("Select folder") , TRUE);
1553 gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0);
1554 gtk_widget_show(label);
1556 pref_line(cd->gd->vbox, PREF_PAD_SPACE);
1557 hbox = pref_box_new(cd->gd->vbox, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
1559 cd->progress = gtk_entry_new();
1560 gtk_widget_set_can_focus(cd->progress, FALSE);
1561 gtk_editable_set_editable(GTK_EDITABLE(cd->progress), FALSE);
1562 gtk_entry_set_text(GTK_ENTRY(cd->progress), _("click start to begin"));
1563 gtk_box_pack_start(GTK_BOX(hbox), cd->progress, TRUE, TRUE, 0);
1564 gtk_widget_show(cd->progress);
1566 cd->progress_bar = gtk_progress_bar_new();
1567 gtk_box_pack_start(GTK_BOX(cd->gd->vbox), cd->progress_bar, TRUE, TRUE, 0);
1568 gtk_widget_show(cd->progress_bar);
1570 cd->spinner = spinner_new(NULL, -1);
1571 gtk_box_pack_start(GTK_BOX(hbox), cd->spinner, FALSE, FALSE, 0);
1572 gtk_widget_show(cd->spinner);
1576 gtk_widget_show(cd->gd->dialog);
1579 static void cache_manager_sim_load_cb(GtkWidget *widget, gpointer UNUSED(data))
1581 const gchar *path = layout_get_path(NULL);
1583 if (!path || !*path) path = homedir();
1584 cache_manager_sim_load_dialog(widget, path);
1587 static void cache_manager_cache_maintenance_close_cb(GenericDialog *UNUSED(fd), gpointer data)
1589 CacheOpsData *cd = data;
1591 if (!gtk_widget_get_sensitive(cd->button_close)) return;
1593 cache_manager_sim_reset(cd);
1594 generic_dialog_close(cd->gd);
1598 static void cache_manager_cache_maintenance_start_cb(GenericDialog *UNUSED(fd), gpointer data)
1600 CacheOpsData *cd = data;
1606 if (cd->list || !gtk_widget_get_sensitive(cd->button_start)) return;
1609 path = remove_trailing_slash((gtk_entry_get_text(GTK_ENTRY(cd->entry))));
1610 parse_out_relatives(path);
1616 warning_dialog(_("Invalid folder"),
1617 _("The specified folder can not be found."),
1618 GTK_STOCK_DIALOG_WARNING, cd->gd->dialog);
1622 log_printf("The specified folder can not be found: \"%s\"\n", path);
1627 cmd_line = g_strdup_printf("%s --cache-maintenance \"%s\"", gq_executable_path, path);
1629 g_spawn_command_line_async(cmd_line, NULL);
1632 generic_dialog_close(cd->gd);
1633 cache_manager_sim_reset(cd);
1640 static void cache_manager_cache_maintenance_load_dialog(GtkWidget *widget, const gchar *path)
1646 cd = g_new0(CacheOpsData, 1);
1650 cd->gd = generic_dialog_new(_("Background cache maintenance"), "background_cache_maintenance", widget, FALSE, NULL, cd);
1651 gtk_window_set_default_size(GTK_WINDOW(cd->gd->dialog), PURGE_DIALOG_WIDTH, -1);
1652 cd->gd->cancel_cb = cache_manager_cache_maintenance_close_cb;
1653 cd->button_close = generic_dialog_add_button(cd->gd, GTK_STOCK_CLOSE, NULL,
1654 cache_manager_cache_maintenance_close_cb, FALSE);
1655 cd->button_start = generic_dialog_add_button(cd->gd, GTK_STOCK_OK, _("S_tart"),
1656 cache_manager_cache_maintenance_start_cb, FALSE);
1658 generic_dialog_add_message(cd->gd, NULL, _("Recursively delete orphaned thumbnails\nand .sim files, and create new\nthumbnails and .sim files"), NULL, FALSE);
1660 hbox = pref_box_new(cd->gd->vbox, FALSE, GTK_ORIENTATION_HORIZONTAL, 0);
1661 pref_spacer(hbox, PREF_PAD_INDENT);
1662 cd->group = pref_box_new(hbox, TRUE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
1664 hbox = pref_box_new(cd->group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
1665 pref_label_new(hbox, _("Folder:"));
1667 label = tab_completion_new(&cd->entry, path, NULL, NULL, NULL, NULL);
1668 tab_completion_add_select_button(cd->entry,_("Select folder") , TRUE);
1669 gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0);
1670 gtk_widget_show(label);
1674 gtk_widget_show(cd->gd->dialog);
1677 static void cache_manager_cache_maintenance_load_cb(GtkWidget *widget, gpointer UNUSED(data))
1679 const gchar *path = layout_get_path(NULL);
1681 if (!path || !*path) path = homedir();
1682 cache_manager_cache_maintenance_load_dialog(widget, path);
1685 void cache_manager_show(void)
1691 GtkSizeGroup *sizegroup;
1696 gtk_window_present(GTK_WINDOW(cache_manager->dialog->dialog));
1700 cache_manager = g_new0(CacheManager, 1);
1702 cache_manager->dialog = generic_dialog_new(_("Cache Maintenance"),
1705 NULL, cache_manager);
1706 gd = cache_manager->dialog;
1708 gd->cancel_cb = cache_manager_close_cb;
1709 generic_dialog_add_button(gd, GTK_STOCK_CLOSE, NULL,
1710 cache_manager_close_cb, FALSE);
1711 generic_dialog_add_button(gd, GTK_STOCK_HELP, NULL,
1712 cache_manager_help_cb, FALSE);
1714 generic_dialog_add_message(gd, NULL, _("Cache and Data Maintenance"), NULL, FALSE);
1716 sizegroup = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
1718 group = pref_group_new(gd->vbox, FALSE, _("Geeqie thumbnail and sim. cache"), GTK_ORIENTATION_VERTICAL);
1720 cache_manager_location_label(group, get_thumbnails_cache_dir());
1722 table = pref_table_new(group, 2, 2, FALSE, FALSE);
1724 button = pref_table_button(table, 0, 0, GTK_STOCK_CLEAR, _("Clean up"), FALSE,
1725 G_CALLBACK(cache_manager_main_clean_cb), cache_manager);
1726 gtk_size_group_add_widget(sizegroup, button);
1727 pref_table_label(table, 1, 0, _("Remove orphaned or outdated thumbnails and sim. files."), 0.0);
1729 button = pref_table_button(table, 0, 1, GTK_STOCK_DELETE, _("Clear cache"), FALSE,
1730 G_CALLBACK(cache_manager_main_clear_cb), cache_manager);
1731 gtk_size_group_add_widget(sizegroup, button);
1732 pref_table_label(table, 1, 1, _("Delete all cached data."), 0.0);
1735 group = pref_group_new(gd->vbox, FALSE, _("Shared thumbnail cache"), GTK_ORIENTATION_VERTICAL);
1737 path = g_build_filename(get_thumbnails_standard_cache_dir(), NULL);
1738 cache_manager_location_label(group, path);
1741 table = pref_table_new(group, 2, 2, FALSE, FALSE);
1743 button = pref_table_button(table, 0, 0, GTK_STOCK_CLEAR, _("Clean up"), FALSE,
1744 G_CALLBACK(cache_manager_standard_clean_cb), cache_manager);
1745 gtk_size_group_add_widget(sizegroup, button);
1746 pref_table_label(table, 1, 0, _("Remove orphaned or outdated thumbnails."), 0.0);
1748 button = pref_table_button(table, 0, 1, GTK_STOCK_DELETE, _("Clear cache"), FALSE,
1749 G_CALLBACK(cache_manager_standard_clear_cb), cache_manager);
1750 gtk_size_group_add_widget(sizegroup, button);
1751 pref_table_label(table, 1, 1, _("Delete all cached thumbnails."), 0.0);
1753 group = pref_group_new(gd->vbox, FALSE, _("Create thumbnails"), GTK_ORIENTATION_VERTICAL);
1755 table = pref_table_new(group, 2, 1, FALSE, FALSE);
1757 button = pref_table_button(table, 0, 1, "system-run", _("Render"), FALSE,
1758 G_CALLBACK(cache_manager_render_cb), cache_manager);
1759 gtk_size_group_add_widget(sizegroup, button);
1760 pref_table_label(table, 1, 1, _("Render thumbnails for a specific folder."), 0.0);
1761 gtk_widget_set_sensitive(group, options->thumbnails.enable_caching);
1763 group = pref_group_new(gd->vbox, FALSE, _("File similarity cache"), GTK_ORIENTATION_VERTICAL);
1765 table = pref_table_new(group, 3, 2, FALSE, FALSE);
1767 button = pref_table_button(table, 0, 0, GTK_STOCK_EXECUTE, _("Create"), FALSE,
1768 G_CALLBACK(cache_manager_sim_load_cb), cache_manager);
1769 gtk_size_group_add_widget(sizegroup, button);
1770 pref_table_label(table, 1, 0, _("Create sim. files recursively."), 0.0);
1771 gtk_widget_set_sensitive(group, options->thumbnails.enable_caching);
1773 group = pref_group_new(gd->vbox, FALSE, _("Metadata"), GTK_ORIENTATION_VERTICAL);
1775 cache_manager_location_label(group, get_metadata_cache_dir());
1777 table = pref_table_new(group, 2, 1, FALSE, FALSE);
1779 button = pref_table_button(table, 0, 0, GTK_STOCK_CLEAR, _("Clean up"), FALSE,
1780 G_CALLBACK(cache_manager_metadata_clean_cb), cache_manager);
1781 gtk_size_group_add_widget(sizegroup, button);
1782 pref_table_label(table, 1, 0, _("Remove orphaned keywords and comments."), 0.0);
1784 group = pref_group_new(gd->vbox, FALSE, _("Background cache maintenance"), GTK_ORIENTATION_VERTICAL);
1786 table = pref_table_new(group, 3, 2, FALSE, FALSE);
1788 button = pref_table_button(table, 0, 0, GTK_STOCK_EXECUTE, _("Select"), FALSE,
1789 G_CALLBACK(cache_manager_cache_maintenance_load_cb), cache_manager);
1790 gtk_size_group_add_widget(sizegroup, button);
1791 pref_table_label(table, 1, 0, _("Run cache maintenance as a background job."), 0.0);
1792 gtk_widget_set_sensitive(group, options->thumbnails.enable_caching);
1794 gtk_widget_show(cache_manager->dialog->dialog);
1796 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */