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.
22 #include "cache-maint.h"
25 #include <sys/types.h>
30 #include <glib-object.h>
32 #include "cache-loader.h"
39 #include "main-defines.h"
43 #include "pixbuf-util.h"
44 #include "thumb-standard.h"
46 #include "ui-fileops.h"
48 #include "ui-tabcomp.h"
49 #include "ui-utildlg.h"
57 guint idle_id; /* event source id */
61 GtkWidget *button_stop;
62 GtkWidget *button_close;
69 PURGE_DIALOG_WIDTH = 400
73 *-----------------------------------------------------------------------------
74 * Command line cache maintenance program functions *-----------------------------------------------------------------------------
76 static gchar *cache_maintenance_path = nullptr;
77 static GtkStatusIcon *status_icon;
79 static void cache_maintenance_sim_stop_cb(gpointer)
84 static void cache_maintenance_render_stop_cb(gpointer)
86 gtk_status_icon_set_tooltip_text(status_icon, _("Geeqie: Creating sim data..."));
87 cache_manager_sim_remote(cache_maintenance_path, TRUE, reinterpret_cast<GDestroyNotify *>(cache_maintenance_sim_stop_cb));
90 static void cache_maintenance_clean_stop_cb(gpointer)
92 gtk_status_icon_set_tooltip_text(status_icon, _("Geeqie: Creating thumbs..."));
93 cache_manager_render_remote(cache_maintenance_path, TRUE, options->thumbnails.cache_into_dirs, reinterpret_cast<GDestroyNotify *>(cache_maintenance_render_stop_cb));
96 static void cache_maintenance_user_cancel_cb()
101 static void cache_maintenance_status_icon_activate_cb(GtkStatusIcon *, gpointer)
106 menu = gtk_menu_new();
108 item = gtk_menu_item_new_with_label(_("Exit Geeqie Cache Maintenance"));
110 g_signal_connect(G_OBJECT(item), "activate", cache_maintenance_user_cancel_cb, item);
111 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
112 gtk_widget_show(item);
114 /* take ownership of menu */
115 g_object_ref_sink(G_OBJECT(menu));
117 gtk_menu_popup_at_pointer(GTK_MENU(menu), nullptr);
120 void cache_maintenance(const gchar *path)
122 cache_maintenance_path = g_strdup(path);
124 status_icon = gtk_status_icon_new_from_pixbuf(pixbuf_inline(PIXBUF_INLINE_ICON));
125 gtk_status_icon_set_tooltip_text(status_icon, _("Geeqie: Cleaning thumbs..."));
126 gtk_status_icon_set_visible(status_icon, TRUE);
127 g_signal_connect(G_OBJECT(status_icon), "activate", G_CALLBACK(cache_maintenance_status_icon_activate_cb), NULL);
129 cache_maintain_home_remote(FALSE, FALSE, reinterpret_cast<GDestroyNotify *>(cache_maintenance_clean_stop_cb));
133 *-------------------------------------------------------------------
135 *-------------------------------------------------------------------
138 static gchar *extension_find_dot(gchar *path)
140 gchar *dot = nullptr;
142 if (!path) return nullptr;
144 while (*path != '\0')
146 if (*path == '.') dot = path;
153 static gboolean isempty(const gchar *path)
159 pathl = path_from_utf8(path);
162 if (!dp) return FALSE;
164 while ((dir = readdir(dp)) != nullptr)
166 gchar *name = dir->d_name;
168 if (name[0] != '.' || (name[1] != '\0' && (name[1] != '.' || name[2] != '\0')) )
179 static void cache_maintain_home_close(CMData *cm)
181 if (cm->idle_id) g_source_remove(cm->idle_id);
182 if (cm->gd) generic_dialog_close(cm->gd);
183 filelist_free(cm->list);
184 g_list_free(cm->done_list);
188 static void cache_maintain_home_stop(CMData *cm)
192 g_source_remove(cm->idle_id);
198 gq_gtk_entry_set_text(GTK_ENTRY(cm->entry), _("done"));
199 gtk_spinner_stop(GTK_SPINNER(cm->spinner));
201 gtk_widget_set_sensitive(cm->button_stop, FALSE);
202 gtk_widget_set_sensitive(cm->button_close, TRUE);
206 static gboolean cache_maintain_home_cb(gpointer data)
208 auto cm = static_cast<CMData *>(data);
209 GList *dlist = nullptr;
210 GList *list = nullptr;
212 gboolean just_done = FALSE;
213 gboolean still_have_a_file = TRUE;
215 const gchar *cache_folder;
216 gboolean filter_disable;
220 cache_folder = get_metadata_cache_dir();
224 cache_folder = get_thumbnails_cache_dir();
227 base_length = strlen(cache_folder);
231 DEBUG_1("purge chk done.");
233 cache_maintain_home_stop(cm);
234 return G_SOURCE_REMOVE;
237 fd = static_cast<FileData *>(cm->list->data);
239 DEBUG_1("purge chk (%d) \"%s\"", (cm->clear && !cm->metadata), fd->path);
242 * It is necessary to disable the file filter when clearing the cache,
243 * otherwise the .sim (file similarity) files are not deleted.
245 filter_disable = options->file_filter.disable;
246 options->file_filter.disable = TRUE;
248 if (g_list_find(cm->done_list, fd) == nullptr)
250 cm->done_list = g_list_prepend(cm->done_list, fd);
252 if (filelist_read(fd, &list, &dlist))
257 still_have_a_file = FALSE;
262 auto fd_list = static_cast<FileData *>(work->data);
263 gchar *path_buf = g_strdup(fd_list->path);
266 dot = extension_find_dot(path_buf);
268 if (dot) *dot = '\0';
269 if ((!cm->metadata && cm->clear) ||
270 (strlen(path_buf) > base_length && !isfile(path_buf + base_length)) )
273 if (!unlink_file(path_buf)) log_printf("failed to delete:%s\n", path_buf);
277 still_have_a_file = TRUE;
284 options->file_filter.disable = filter_disable;
288 cm->list = g_list_concat(dlist, cm->list);
290 if (cm->list && g_list_find(cm->done_list, cm->list->data) != nullptr)
292 /* check if the dir is empty */
294 if (cm->list->data == fd && just_done)
296 if (!still_have_a_file && !dlist && cm->list->next && !rmdir_utf8(fd->path))
298 log_printf("Unable to delete dir: %s\n", fd->path);
303 /* must re-check for an empty dir */
304 if (isempty(fd->path) && cm->list->next && !rmdir_utf8(fd->path))
306 log_printf("Unable to delete dir: %s\n", fd->path);
310 fd = static_cast<FileData *>(cm->list->data);
311 cm->done_list = g_list_remove(cm->done_list, fd);
312 cm->list = g_list_remove(cm->list, fd);
316 if (cm->list && !cm->remote)
320 fd = static_cast<FileData *>(cm->list->data);
321 if (strlen(fd->path) > base_length)
323 buf = fd->path + base_length;
329 gq_gtk_entry_set_text(GTK_ENTRY(cm->entry), buf);
332 return G_SOURCE_CONTINUE;
335 static void cache_maintain_home_close_cb(GenericDialog *, gpointer data)
337 auto cm = static_cast<CMData *>(data);
339 if (!gtk_widget_get_sensitive(cm->button_close)) return;
341 cache_maintain_home_close(cm);
344 static void cache_maintain_home_stop_cb(GenericDialog *, gpointer data)
346 auto cm = static_cast<CMData *>(data);
348 cache_maintain_home_stop(cm);
351 /* sorry for complexity (cm->done_list), but need it to remove empty dirs */
352 void cache_maintain_home(gboolean metadata, gboolean clear, GtkWidget *parent)
358 const gchar *cache_folder;
363 cache_folder = get_metadata_cache_dir();
367 cache_folder = get_thumbnails_cache_dir();
370 dir_fd = file_data_new_dir(cache_folder);
371 if (!filelist_read(dir_fd, nullptr, &dlist))
373 file_data_unref(dir_fd);
377 dlist = g_list_append(dlist, dir_fd);
379 cm = g_new0(CMData, 1);
381 cm->done_list = nullptr;
383 cm->metadata = metadata;
388 msg = _("Removing old metadata...");
392 msg = _("Clearing cached thumbnails...");
396 msg = _("Removing old thumbnails...");
399 cm->gd = generic_dialog_new(_("Maintenance"),
403 cm->gd->cancel_cb = cache_maintain_home_close_cb;
404 cm->button_close = generic_dialog_add_button(cm->gd, GQ_ICON_CLOSE, _("Close"),
405 cache_maintain_home_close_cb, FALSE);
406 gtk_widget_set_sensitive(cm->button_close, FALSE);
407 cm->button_stop = generic_dialog_add_button(cm->gd, GQ_ICON_STOP, _("Stop"),
408 cache_maintain_home_stop_cb, FALSE);
410 generic_dialog_add_message(cm->gd, nullptr, msg, nullptr, FALSE);
411 gtk_window_set_default_size(GTK_WINDOW(cm->gd->dialog), PURGE_DIALOG_WIDTH, -1);
413 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
414 gq_gtk_box_pack_start(GTK_BOX(cm->gd->vbox), hbox, FALSE, FALSE, 5);
415 gtk_widget_show(hbox);
417 cm->entry = gtk_entry_new();
418 gtk_widget_set_can_focus(cm->entry, FALSE);
419 gtk_editable_set_editable(GTK_EDITABLE(cm->entry), FALSE);
420 gq_gtk_box_pack_start(GTK_BOX(hbox), cm->entry, TRUE, TRUE, 0);
421 gtk_widget_show(cm->entry);
423 cm->spinner = gtk_spinner_new();
424 gtk_spinner_start(GTK_SPINNER(cm->spinner));
425 gq_gtk_box_pack_start(GTK_BOX(hbox), cm->spinner, FALSE, FALSE, 0);
426 gtk_widget_show(cm->spinner);
428 gtk_widget_show(cm->gd->dialog);
430 cm->idle_id = g_idle_add(cache_maintain_home_cb, cm);
434 * @brief Clears or culls cached data
435 * @param metadata TRUE - work on metadata cache, FALSE - work on thumbnail cache
436 * @param clear TRUE - clear cache, FALSE - delete orphaned cached items
437 * @param func Function called when idle loop function terminates
441 void cache_maintain_home_remote(gboolean metadata, gboolean clear, GDestroyNotify *func)
446 const gchar *cache_folder;
450 cache_folder = get_metadata_cache_dir();
454 cache_folder = get_thumbnails_cache_dir();
457 dir_fd = file_data_new_dir(cache_folder);
458 if (!filelist_read(dir_fd, nullptr, &dlist))
460 file_data_unref(dir_fd);
464 dlist = g_list_append(dlist, dir_fd);
466 cm = g_new0(CMData, 1);
468 cm->done_list = nullptr;
470 cm->metadata = metadata;
473 cm->idle_id = g_idle_add_full(G_PRIORITY_LOW, cache_maintain_home_cb, cm, reinterpret_cast<GDestroyNotify>(func));
476 static void cache_file_move(const gchar *src, const gchar *dest)
478 if (!dest || !src || !isfile(src)) return;
480 if (!move_file(src, dest))
482 DEBUG_1("Failed to move cache file \"%s\" to \"%s\"", src, dest);
483 /* we remove it anyway - it's stale */
488 static void cache_maint_moved(FileData *fd)
492 const gchar *src = fd->change->source;
493 const gchar *dest = fd->change->dest;
495 if (!src || !dest) return;
497 base = cache_get_location(CACHE_TYPE_THUMB, dest, FALSE, &mode);
498 if (recursive_mkdir_if_not_exists(base, mode))
503 buf = cache_find_location(CACHE_TYPE_THUMB, src);
504 d = cache_get_location(CACHE_TYPE_THUMB, dest, TRUE, nullptr);
505 cache_file_move(buf, d);
509 buf = cache_find_location(CACHE_TYPE_SIM, src);
510 d = cache_get_location(CACHE_TYPE_SIM, dest, TRUE, nullptr);
511 cache_file_move(buf, d);
517 log_printf("Failed to create cache dir for move %s\n", base);
521 base = cache_get_location(CACHE_TYPE_METADATA, dest, FALSE, &mode);
522 if (recursive_mkdir_if_not_exists(base, mode))
527 buf = cache_find_location(CACHE_TYPE_METADATA, src);
528 d = cache_get_location(CACHE_TYPE_METADATA, dest, TRUE, nullptr);
529 cache_file_move(buf, d);
535 if (options->thumbnails.enable_caching && options->thumbnails.spec_standard)
536 thumb_std_maint_moved(src, dest);
539 static void cache_file_remove(const gchar *path)
541 if (path && isfile(path) && !unlink_file(path))
543 DEBUG_1("Failed to remove cache file %s", path);
547 static void cache_maint_removed(FileData *fd)
551 buf = cache_find_location(CACHE_TYPE_THUMB, fd->path);
552 cache_file_remove(buf);
555 buf = cache_find_location(CACHE_TYPE_SIM, fd->path);
556 cache_file_remove(buf);
559 buf = cache_find_location(CACHE_TYPE_METADATA, fd->path);
560 cache_file_remove(buf);
563 if (options->thumbnails.enable_caching && options->thumbnails.spec_standard)
564 thumb_std_maint_removed(fd->path);
567 static void cache_maint_copied(FileData *fd)
573 src_cache = cache_find_location(CACHE_TYPE_METADATA, fd->change->source);
574 if (!src_cache) return;
576 dest_base = cache_get_location(CACHE_TYPE_METADATA, fd->change->dest, FALSE, &mode);
577 if (recursive_mkdir_if_not_exists(dest_base, mode))
581 path = cache_get_location(CACHE_TYPE_METADATA, fd->change->dest, TRUE, nullptr);
582 if (!copy_file(src_cache, path))
584 DEBUG_1("failed to copy metadata %s to %s", src_cache, path);
593 void cache_notify_cb(FileData *fd, NotifyType type, gpointer)
595 if (!(type & NOTIFY_CHANGE) || !fd->change) return;
597 DEBUG_1("Notify cache_maint: %s %04x", fd->path, type);
598 switch (fd->change->type)
600 case FILEDATA_CHANGE_MOVE:
601 case FILEDATA_CHANGE_RENAME:
602 cache_maint_moved(fd);
604 case FILEDATA_CHANGE_COPY:
605 cache_maint_copied(fd);
607 case FILEDATA_CHANGE_DELETE:
608 cache_maint_removed(fd);
610 case FILEDATA_CHANGE_UNSPECIFIED:
611 case FILEDATA_CHANGE_WRITE_METADATA:
618 *-------------------------------------------------------------------
619 * new cache maintenance utilities
620 *-------------------------------------------------------------------
625 GenericDialog *dialog;
626 GtkWidget *folder_entry;
640 GDestroyNotify *destroy_func; /* Used by the command line prog. functions */
648 GtkWidget *button_close;
649 GtkWidget *button_stop;
650 GtkWidget *button_start;
652 GtkWidget *progress_bar;
666 guint idle_id; /* event source id */
669 static void cache_manager_render_reset(CacheOpsData *cd)
671 filelist_free(cd->list);
674 filelist_free(cd->list_dir);
675 cd->list_dir = nullptr;
677 thumb_loader_free(reinterpret_cast<ThumbLoader *>(cd->tl));
681 static void cache_manager_render_close_cb(GenericDialog *, gpointer data)
683 auto cd = static_cast<CacheOpsData *>(data);
685 if (!gtk_widget_get_sensitive(cd->button_close)) return;
687 cache_manager_render_reset(cd);
688 generic_dialog_close(cd->gd);
692 static void cache_manager_render_finish(CacheOpsData *cd)
694 cache_manager_render_reset(cd);
697 gq_gtk_entry_set_text(GTK_ENTRY(cd->progress), _("done"));
698 gtk_spinner_stop(GTK_SPINNER(cd->spinner));
700 gtk_widget_set_sensitive(cd->group, TRUE);
701 gtk_widget_set_sensitive(cd->button_start, TRUE);
702 gtk_widget_set_sensitive(cd->button_stop, FALSE);
703 gtk_widget_set_sensitive(cd->button_close, TRUE);
707 static void cache_manager_render_stop_cb(GenericDialog *, gpointer data)
709 auto cd = static_cast<CacheOpsData *>(data);
711 gq_gtk_entry_set_text(GTK_ENTRY(cd->progress), _("stopped"));
712 cache_manager_render_finish(cd);
715 static void cache_manager_render_folder(CacheOpsData *cd, FileData *dir_fd)
717 GList *list_d = nullptr;
718 GList *list_f = nullptr;
722 filelist_read(dir_fd, &list_f, &list_d);
726 filelist_read(dir_fd, &list_f, nullptr);
729 list_f = filelist_filter(list_f, FALSE);
730 list_d = filelist_filter(list_d, TRUE);
732 cd->list = g_list_concat(list_f, cd->list);
733 cd->list_dir = g_list_concat(list_d, cd->list_dir);
736 static gboolean cache_manager_render_file(CacheOpsData *cd);
738 static void cache_manager_render_thumb_done_cb(ThumbLoader *, gpointer data)
740 auto cd = static_cast<CacheOpsData *>(data);
742 thumb_loader_free(reinterpret_cast<ThumbLoader *>(cd->tl));
745 while (cache_manager_render_file(cd));
748 static gboolean cache_manager_render_file(CacheOpsData *cd)
755 fd = static_cast<FileData *>(cd->list->data);
756 cd->list = g_list_remove(cd->list, fd);
758 cd->tl = reinterpret_cast<ThumbLoaderStd *>(thumb_loader_new(options->thumbnails.max_width, options->thumbnails.max_height));
759 thumb_loader_set_callbacks(reinterpret_cast<ThumbLoader *>(cd->tl),
760 cache_manager_render_thumb_done_cb,
761 cache_manager_render_thumb_done_cb,
763 thumb_loader_set_cache(reinterpret_cast<ThumbLoader *>(cd->tl), TRUE, cd->local, TRUE);
764 success = thumb_loader_start(reinterpret_cast<ThumbLoader *>(cd->tl), fd);
769 gq_gtk_entry_set_text(GTK_ENTRY(cd->progress), fd->path);
770 cd->count_done = cd->count_done + 1;
771 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(cd->progress_bar), static_cast<gdouble>(cd->count_done) / cd->count_total);
776 thumb_loader_free(reinterpret_cast<ThumbLoader *>(cd->tl));
788 fd = static_cast<FileData *>(cd->list_dir->data);
789 cd->list_dir = g_list_remove(cd->list_dir, fd);
791 cache_manager_render_folder(cd, fd);
800 gq_gtk_entry_set_text(GTK_ENTRY(cd->progress), _("done"));
802 cache_manager_render_finish(cd);
804 if (cd->destroy_func)
806 g_idle_add(reinterpret_cast<GSourceFunc>(cd->destroy_func), nullptr);
812 static void cache_manager_render_start_cb(GenericDialog *, gpointer data)
814 auto cd = static_cast<CacheOpsData *>(data);
816 GList *list_total = nullptr;
820 if (cd->list || !gtk_widget_get_sensitive(cd->button_start)) return;
823 path = remove_trailing_slash((gq_gtk_entry_get_text(GTK_ENTRY(cd->entry))));
824 parse_out_relatives(path);
830 warning_dialog(_("Invalid folder"),
831 _("The specified folder can not be found."),
832 GQ_ICON_DIALOG_WARNING, cd->gd->dialog);
836 log_printf("The specified folder can not be found: %s\n", path);
844 gtk_widget_set_sensitive(cd->group, FALSE);
845 gtk_widget_set_sensitive(cd->button_start, FALSE);
846 gtk_widget_set_sensitive(cd->button_stop, TRUE);
847 gtk_widget_set_sensitive(cd->button_close, FALSE);
849 gtk_spinner_start(GTK_SPINNER(cd->spinner));
851 dir_fd = file_data_new_dir(path);
852 cache_manager_render_folder(cd, dir_fd);
853 list_total = filelist_recursive(dir_fd);
854 cd->count_total = g_list_length(list_total);
855 file_data_unref(dir_fd);
856 g_list_free(list_total);
859 while (cache_manager_render_file(cd));
865 static void cache_manager_render_start_render_remote(CacheOpsData *cd, const gchar *user_path)
869 path = remove_trailing_slash(user_path);
870 parse_out_relatives(path);
874 log_printf("The specified folder can not be found: %s\n", path);
880 dir_fd = file_data_new_dir(path);
881 cache_manager_render_folder(cd, dir_fd);
882 file_data_unref(dir_fd);
883 while (cache_manager_render_file(cd));
889 static void cache_manager_render_dialog(GtkWidget *widget, const gchar *path)
896 cd = g_new0(CacheOpsData, 1);
899 cd->gd = generic_dialog_new(_("Create thumbnails"),
903 gtk_window_set_default_size(GTK_WINDOW(cd->gd->dialog), PURGE_DIALOG_WIDTH, -1);
904 cd->gd->cancel_cb = cache_manager_render_close_cb;
905 cd->button_close = generic_dialog_add_button(cd->gd, GQ_ICON_CLOSE, _("Close"),
906 cache_manager_render_close_cb, FALSE);
907 cd->button_start = generic_dialog_add_button(cd->gd, GQ_ICON_OK, _("S_tart"),
908 cache_manager_render_start_cb, FALSE);
909 cd->button_stop = generic_dialog_add_button(cd->gd, GQ_ICON_STOP, _("Stop"),
910 cache_manager_render_stop_cb, FALSE);
911 gtk_widget_set_sensitive(cd->button_stop, FALSE);
913 generic_dialog_add_message(cd->gd, nullptr, _("Create thumbnails"), nullptr, FALSE);
915 hbox = pref_box_new(cd->gd->vbox, FALSE, GTK_ORIENTATION_HORIZONTAL, 0);
916 pref_spacer(hbox, PREF_PAD_INDENT);
917 cd->group = pref_box_new(hbox, TRUE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
919 hbox = pref_box_new(cd->group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
920 pref_label_new(hbox, _("Folder:"));
922 label = tab_completion_new(&cd->entry, path, nullptr, nullptr, nullptr, nullptr);
923 tab_completion_add_select_button(cd->entry,_("Select folder") , TRUE);
924 gq_gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0);
925 gtk_widget_show(label);
927 pref_checkbox_new_int(cd->group, _("Include subfolders"), FALSE, &cd->recurse);
928 button = pref_checkbox_new_int(cd->group, _("Store thumbnails local to source images"), FALSE, &cd->local);
929 gtk_widget_set_sensitive(button, options->thumbnails.spec_standard);
931 pref_line(cd->gd->vbox, PREF_PAD_SPACE);
932 hbox = pref_box_new(cd->gd->vbox, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
934 cd->progress = gtk_entry_new();
935 gtk_widget_set_can_focus(cd->progress, FALSE);
936 gtk_editable_set_editable(GTK_EDITABLE(cd->progress), FALSE);
937 gq_gtk_entry_set_text(GTK_ENTRY(cd->progress), _("click start to begin"));
938 gq_gtk_box_pack_start(GTK_BOX(hbox), cd->progress, TRUE, TRUE, 0);
939 gtk_widget_show(cd->progress);
941 cd->progress_bar = gtk_progress_bar_new();
942 gq_gtk_box_pack_start(GTK_BOX(cd->gd->vbox), cd->progress_bar, TRUE, TRUE, 0);
943 gtk_widget_show(cd->progress_bar);
945 cd->spinner = gtk_spinner_new();
946 gq_gtk_box_pack_start(GTK_BOX(hbox), cd->spinner, FALSE, FALSE, 0);
947 gtk_widget_show(cd->spinner);
951 gtk_widget_show(cd->gd->dialog);
955 * @brief Create thumbnails
956 * @param path Path to image folder
958 * @param local Create thumbnails in same folder as images
959 * @param func Function called when idle loop function terminates
963 void cache_manager_render_remote(const gchar *path, gboolean recurse, gboolean local, GDestroyNotify *func)
967 cd = g_new0(CacheOpsData, 1);
968 cd->recurse = recurse;
971 cd->destroy_func = func;
973 cache_manager_render_start_render_remote(cd, path);
976 static void cache_manager_standard_clean_close_cb(GenericDialog *, gpointer data)
978 auto cd = static_cast<CacheOpsData *>(data);
980 if (!gtk_widget_get_sensitive(cd->button_close)) return;
982 generic_dialog_close(cd->gd);
984 thumb_loader_std_thumb_file_validate_cancel(cd->tl);
985 filelist_free(cd->list);
989 static void cache_manager_standard_clean_done(CacheOpsData *cd)
993 gtk_widget_set_sensitive(cd->button_stop, FALSE);
994 gtk_widget_set_sensitive(cd->button_close, TRUE);
996 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(cd->progress), 1.0);
997 gtk_progress_bar_set_text(GTK_PROGRESS_BAR(cd->progress), _("done"));
1001 g_source_remove(cd->idle_id);
1005 thumb_loader_std_thumb_file_validate_cancel(cd->tl);
1008 filelist_free(cd->list);
1012 static void cache_manager_standard_clean_stop_cb(GenericDialog *, gpointer data)
1014 auto cd = static_cast<CacheOpsData *>(data);
1016 cache_manager_standard_clean_done(cd);
1019 static gint cache_manager_standard_clean_clear_cb(gpointer data)
1021 auto cd = static_cast<CacheOpsData *>(data);
1027 next_fd = static_cast<FileData *>(cd->list->data);
1028 cd->list = g_list_remove(cd->list, next_fd);
1030 DEBUG_1("thumb removed: %s", next_fd->path);
1032 unlink_file(next_fd->path);
1033 file_data_unref(next_fd);
1038 if (cd->count_total != 0)
1040 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(cd->progress),
1041 static_cast<gdouble>(cd->count_done) / cd->count_total);
1045 return G_SOURCE_CONTINUE;
1049 cache_manager_standard_clean_done(cd);
1050 return G_SOURCE_REMOVE;
1053 static void cache_manager_standard_clean_valid_cb(const gchar *path, gboolean valid, gpointer data)
1055 auto cd = static_cast<CacheOpsData *>(data);
1061 DEBUG_1("thumb cleaned: %s", path);
1068 if (cd->count_total != 0)
1070 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(cd->progress),
1071 static_cast<gdouble>(cd->count_done) / cd->count_total);
1081 next_fd = static_cast<FileData *>(cd->list->data);
1082 cd->list = g_list_remove(cd->list, next_fd);
1084 cd->tl = thumb_loader_std_thumb_file_validate(next_fd->path, cd->days,
1085 cache_manager_standard_clean_valid_cb, cd);
1086 file_data_unref(next_fd);
1090 cache_manager_standard_clean_done(cd);
1094 static void cache_manager_standard_clean_start(GenericDialog *, gpointer data)
1096 auto cd = static_cast<CacheOpsData *>(data);
1103 if (cd->list || !gtk_widget_get_sensitive(cd->button_start)) return;
1105 gtk_widget_set_sensitive(cd->button_start, FALSE);
1106 gtk_widget_set_sensitive(cd->button_stop, TRUE);
1107 gtk_widget_set_sensitive(cd->button_close, FALSE);
1109 gtk_progress_bar_set_text(GTK_PROGRESS_BAR(cd->progress), _("running..."));
1112 path = g_build_filename(get_thumbnails_standard_cache_dir(), THUMB_FOLDER_NORMAL, NULL);
1113 dir_fd = file_data_new_dir(path);
1114 filelist_read(dir_fd, &list, nullptr);
1116 file_data_unref(dir_fd);
1119 path = g_build_filename(get_thumbnails_standard_cache_dir(), THUMB_FOLDER_LARGE, NULL);
1120 dir_fd = file_data_new_dir(path);
1121 filelist_read(dir_fd, &list, nullptr);
1122 cd->list = g_list_concat(cd->list, list);
1123 file_data_unref(dir_fd);
1126 path = g_build_filename(get_thumbnails_standard_cache_dir(), THUMB_FOLDER_FAIL, NULL);
1127 dir_fd = file_data_new_dir(path);
1128 filelist_read(dir_fd, &list, nullptr);
1129 cd->list = g_list_concat(cd->list, list);
1130 file_data_unref(dir_fd);
1133 cd->count_total = g_list_length(cd->list);
1136 /* start iterating */
1139 cd->idle_id = g_idle_add(cache_manager_standard_clean_clear_cb, cd);
1143 cache_manager_standard_clean_valid_cb(nullptr, TRUE, cd);
1147 static void cache_manager_standard_clean_start_cb(GenericDialog *gd, gpointer data)
1149 cache_manager_standard_clean_start(gd, data);
1152 static void cache_manager_standard_process(GtkWidget *widget, gboolean clear)
1155 const gchar *icon_name;
1158 cd = g_new0(CacheOpsData, 1);
1164 icon_name = GQ_ICON_DELETE;
1165 msg = _("Clearing thumbnails...");
1169 icon_name = GQ_ICON_CLEAR;
1170 msg = _("Removing old thumbnails...");
1173 cd->gd = generic_dialog_new(_("Maintenance"),
1174 "standard_maintenance",
1177 cd->gd->cancel_cb = cache_manager_standard_clean_close_cb;
1178 cd->button_close = generic_dialog_add_button(cd->gd, GQ_ICON_CLOSE, _("Close"),
1179 cache_manager_standard_clean_close_cb, FALSE);
1180 cd->button_start = generic_dialog_add_button(cd->gd, GQ_ICON_OK, _("S_tart"),
1181 cache_manager_standard_clean_start_cb, FALSE);
1182 cd->button_stop = generic_dialog_add_button(cd->gd, GQ_ICON_STOP, _("Stop"),
1183 cache_manager_standard_clean_stop_cb, FALSE);
1184 gtk_widget_set_sensitive(cd->button_stop, FALSE);
1186 generic_dialog_add_message(cd->gd, icon_name, msg, nullptr, FALSE);
1188 cd->progress = gtk_progress_bar_new();
1189 gtk_progress_bar_set_text(GTK_PROGRESS_BAR(cd->progress), _("click start to begin"));
1190 gtk_progress_bar_set_show_text(GTK_PROGRESS_BAR(cd->progress), TRUE);
1191 gq_gtk_box_pack_start(GTK_BOX(cd->gd->vbox), cd->progress, FALSE, FALSE, 0);
1192 gtk_widget_show(cd->progress);
1198 gtk_widget_show(cd->gd->dialog);
1201 void cache_manager_standard_process_remote(gboolean clear)
1205 cd = g_new0(CacheOpsData, 1);
1212 cache_manager_standard_clean_start(nullptr, cd);
1215 static void cache_manager_standard_clean_cb(GtkWidget *widget, gpointer)
1217 cache_manager_standard_process(widget, FALSE);
1220 static void cache_manager_standard_clear_cb(GtkWidget *widget, gpointer)
1222 cache_manager_standard_process(widget, TRUE);
1226 static void cache_manager_main_clean_cb(GtkWidget *widget, gpointer)
1228 cache_maintain_home(FALSE, FALSE, widget);
1232 static void dummy_cancel_cb(GenericDialog *, gpointer)
1234 /* no op, only so cancel button appears */
1237 static void cache_manager_main_clear_ok_cb(GenericDialog *, gpointer)
1239 cache_maintain_home(FALSE, TRUE, nullptr);
1242 void cache_manager_main_clear_confirm(GtkWidget *parent)
1246 gd = generic_dialog_new(_("Clear cache"),
1247 "clear_cache", parent, TRUE,
1248 dummy_cancel_cb, nullptr);
1249 generic_dialog_add_message(gd, GQ_ICON_DIALOG_QUESTION, _("Clear cache"),
1250 _("This will remove all thumbnails and sim. files\nthat have been saved to disk, continue?"), TRUE);
1251 generic_dialog_add_button(gd, GQ_ICON_OK, "OK", cache_manager_main_clear_ok_cb, TRUE);
1253 gtk_widget_show(gd->dialog);
1256 static void cache_manager_main_clear_cb(GtkWidget *widget, gpointer)
1258 cache_manager_main_clear_confirm(widget);
1261 static void cache_manager_render_cb(GtkWidget *widget, gpointer)
1263 const gchar *path = layout_get_path(nullptr);
1265 if (!path || !*path) path = homedir();
1266 cache_manager_render_dialog(widget, path);
1269 static void cache_manager_metadata_clean_cb(GtkWidget *widget, gpointer)
1271 cache_maintain_home(TRUE, FALSE, widget);
1275 static CacheManager *cache_manager = nullptr;
1277 static void cache_manager_close_cb(GenericDialog *gd, gpointer)
1279 generic_dialog_close(gd);
1281 g_free(cache_manager);
1282 cache_manager = nullptr;
1285 static void cache_manager_help_cb(GenericDialog *, gpointer)
1287 help_window_show("GuideReferenceManagement.html");
1290 static GtkWidget *cache_manager_location_label(GtkWidget *group, const gchar *subdir)
1295 buf = g_strdup_printf(_("Location: %s"), subdir);
1296 label = pref_label_new(group, buf);
1298 gtk_label_set_xalign(GTK_LABEL(label), 0.0);
1299 gtk_label_set_yalign(GTK_LABEL(label), 0.5);
1304 static gboolean cache_manager_sim_file(CacheOpsData *cd);
1306 static void cache_manager_sim_reset(CacheOpsData *cd)
1308 filelist_free(cd->list);
1311 filelist_free(cd->list_dir);
1312 cd->list_dir = nullptr;
1314 cache_loader_free(cd->cl);
1318 static void cache_manager_sim_close_cb(GenericDialog *, gpointer data)
1320 auto cd = static_cast<CacheOpsData *>(data);
1322 if (!gtk_widget_get_sensitive(cd->button_close)) return;
1324 cache_manager_sim_reset(cd);
1325 generic_dialog_close(cd->gd);
1329 static void cache_manager_sim_finish(CacheOpsData *cd)
1331 cache_manager_sim_reset(cd);
1334 gtk_spinner_stop(GTK_SPINNER(cd->spinner));
1336 gtk_widget_set_sensitive(cd->group, TRUE);
1337 gtk_widget_set_sensitive(cd->button_start, TRUE);
1338 gtk_widget_set_sensitive(cd->button_stop, FALSE);
1339 gtk_widget_set_sensitive(cd->button_close, TRUE);
1343 static void cache_manager_sim_stop_cb(GenericDialog *, gpointer data)
1345 auto cd = static_cast<CacheOpsData *>(data);
1347 gq_gtk_entry_set_text(GTK_ENTRY(cd->progress), _("stopped"));
1348 cache_manager_sim_finish(cd);
1351 static void cache_manager_sim_folder(CacheOpsData *cd, FileData *dir_fd)
1353 GList *list_d = nullptr;
1354 GList *list_f = nullptr;
1358 filelist_read(dir_fd, &list_f, &list_d);
1362 filelist_read(dir_fd, &list_f, nullptr);
1365 list_f = filelist_filter(list_f, FALSE);
1366 list_d = filelist_filter(list_d, TRUE);
1368 cd->list = g_list_concat(list_f, cd->list);
1369 cd->list_dir = g_list_concat(list_d, cd->list_dir);
1372 static void cache_manager_sim_file_done_cb(CacheLoader *, gint, gpointer data)
1374 auto cd = static_cast<CacheOpsData *>(data);
1376 cache_loader_free(cd->cl);
1379 while (cache_manager_sim_file(cd));
1382 static void cache_manager_sim_start_sim_remote(CacheOpsData *cd, const gchar *user_path)
1386 path = remove_trailing_slash(user_path);
1387 parse_out_relatives(path);
1391 log_printf("The specified folder can not be found: %s\n", path);
1397 dir_fd = file_data_new_dir(path);
1398 cache_manager_sim_folder(cd, dir_fd);
1399 file_data_unref(dir_fd);
1400 while (cache_manager_sim_file(cd));
1407 * @brief Generate .sim files
1408 * @param path Path to image folder
1410 * @param func Function called when idle loop function terminates
1414 void cache_manager_sim_remote(const gchar *path, gboolean recurse, GDestroyNotify *func)
1418 cd = g_new0(CacheOpsData, 1);
1419 cd->recurse = recurse;
1421 cd->destroy_func = func;
1423 cache_manager_sim_start_sim_remote(cd, path);
1426 static gboolean cache_manager_sim_file(CacheOpsData *cd)
1428 CacheDataType load_mask;
1433 fd = static_cast<FileData *>(cd->list->data);
1434 cd->list = g_list_remove(cd->list, fd);
1436 load_mask = static_cast<CacheDataType>(CACHE_LOADER_DIMENSIONS | CACHE_LOADER_DATE | CACHE_LOADER_MD5SUM | CACHE_LOADER_SIMILARITY);
1437 cd->cl = cache_loader_new(fd, load_mask, (cache_manager_sim_file_done_cb), cd);
1441 gq_gtk_entry_set_text(GTK_ENTRY(cd->progress), fd->path);
1444 file_data_unref(fd);
1445 cd->count_done = cd->count_done + 1;
1448 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(cd->progress_bar), static_cast<gdouble>(cd->count_done) / cd->count_total);
1457 fd = static_cast<FileData *>(cd->list_dir->data);
1458 cd->list_dir = g_list_remove(cd->list_dir, fd);
1460 cache_manager_sim_folder(cd, fd);
1461 file_data_unref(fd);
1468 gq_gtk_entry_set_text(GTK_ENTRY(cd->progress), _("done"));
1471 cache_manager_sim_finish(cd);
1473 if (cd->destroy_func)
1475 g_idle_add(reinterpret_cast<GSourceFunc>(cd->destroy_func), nullptr);
1481 static void cache_manager_sim_start_cb(GenericDialog *, gpointer data)
1483 auto cd = static_cast<CacheOpsData *>(data);
1485 GList *list_total = nullptr;
1489 if (cd->list || !gtk_widget_get_sensitive(cd->button_start)) return;
1492 path = remove_trailing_slash((gq_gtk_entry_get_text(GTK_ENTRY(cd->entry))));
1493 parse_out_relatives(path);
1499 warning_dialog(_("Invalid folder"),
1500 _("The specified folder can not be found."),
1501 GQ_ICON_DIALOG_WARNING, cd->gd->dialog);
1505 log_printf("The specified folder can not be found: %s\n", path);
1513 gtk_widget_set_sensitive(cd->group, FALSE);
1514 gtk_widget_set_sensitive(cd->button_start, FALSE);
1515 gtk_widget_set_sensitive(cd->button_stop, TRUE);
1516 gtk_widget_set_sensitive(cd->button_close, FALSE);
1518 gtk_spinner_start(GTK_SPINNER(cd->spinner));
1520 dir_fd = file_data_new_dir(path);
1521 cache_manager_sim_folder(cd, dir_fd);
1522 list_total = filelist_recursive(dir_fd);
1523 cd->count_total = g_list_length(list_total);
1524 file_data_unref(dir_fd);
1525 g_list_free(list_total);
1528 while (cache_manager_sim_file(static_cast<CacheOpsData *>(cd)));
1534 static void cache_manager_sim_load_dialog(GtkWidget *widget, const gchar *path)
1540 cd = g_new0(CacheOpsData, 1);
1544 cd->gd = generic_dialog_new(_("Create sim. files"), "create_sim_files", widget, FALSE, nullptr, cd);
1545 gtk_window_set_default_size(GTK_WINDOW(cd->gd->dialog), PURGE_DIALOG_WIDTH, -1);
1546 cd->gd->cancel_cb = cache_manager_sim_close_cb;
1547 cd->button_close = generic_dialog_add_button(cd->gd, GQ_ICON_CLOSE, _("Close"),
1548 cache_manager_sim_close_cb, FALSE);
1549 cd->button_start = generic_dialog_add_button(cd->gd, GQ_ICON_OK, _("S_tart"),
1550 cache_manager_sim_start_cb, FALSE);
1551 cd->button_stop = generic_dialog_add_button(cd->gd, GQ_ICON_STOP, _("Stop"),
1552 cache_manager_sim_stop_cb, FALSE);
1553 gtk_widget_set_sensitive(cd->button_stop, FALSE);
1555 generic_dialog_add_message(cd->gd, nullptr, _("Create sim. files recursively"), nullptr, FALSE);
1557 hbox = pref_box_new(cd->gd->vbox, FALSE, GTK_ORIENTATION_HORIZONTAL, 0);
1558 pref_spacer(hbox, PREF_PAD_INDENT);
1559 cd->group = pref_box_new(hbox, TRUE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
1561 hbox = pref_box_new(cd->group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
1562 pref_label_new(hbox, _("Folder:"));
1564 label = tab_completion_new(&cd->entry, path, nullptr, nullptr, nullptr, nullptr);
1565 tab_completion_add_select_button(cd->entry,_("Select folder") , TRUE);
1566 gq_gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0);
1567 gtk_widget_show(label);
1569 pref_line(cd->gd->vbox, PREF_PAD_SPACE);
1570 hbox = pref_box_new(cd->gd->vbox, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
1572 cd->progress = gtk_entry_new();
1573 gtk_widget_set_can_focus(cd->progress, FALSE);
1574 gtk_editable_set_editable(GTK_EDITABLE(cd->progress), FALSE);
1575 gq_gtk_entry_set_text(GTK_ENTRY(cd->progress), _("click start to begin"));
1576 gq_gtk_box_pack_start(GTK_BOX(hbox), cd->progress, TRUE, TRUE, 0);
1577 gtk_widget_show(cd->progress);
1579 cd->progress_bar = gtk_progress_bar_new();
1580 gq_gtk_box_pack_start(GTK_BOX(cd->gd->vbox), cd->progress_bar, TRUE, TRUE, 0);
1581 gtk_widget_show(cd->progress_bar);
1583 cd->spinner = gtk_spinner_new();
1584 gq_gtk_box_pack_start(GTK_BOX(hbox), cd->spinner, FALSE, FALSE, 0);
1585 gtk_widget_show(cd->spinner);
1589 gtk_widget_show(cd->gd->dialog);
1592 static void cache_manager_sim_load_cb(GtkWidget *widget, gpointer)
1594 const gchar *path = layout_get_path(nullptr);
1596 if (!path || !*path) path = homedir();
1597 cache_manager_sim_load_dialog(widget, path);
1600 static void cache_manager_cache_maintenance_close_cb(GenericDialog *, gpointer data)
1602 auto cd = static_cast<CacheOpsData *>(data);
1604 if (!gtk_widget_get_sensitive(cd->button_close)) return;
1606 cache_manager_sim_reset(cd);
1607 generic_dialog_close(cd->gd);
1611 static void cache_manager_cache_maintenance_start_cb(GenericDialog *, gpointer data)
1613 auto cd = static_cast<CacheOpsData *>(data);
1619 if (cd->list || !gtk_widget_get_sensitive(cd->button_start)) return;
1622 path = remove_trailing_slash((gq_gtk_entry_get_text(GTK_ENTRY(cd->entry))));
1623 parse_out_relatives(path);
1629 warning_dialog(_("Invalid folder"),
1630 _("The specified folder can not be found."),
1631 GQ_ICON_DIALOG_WARNING, cd->gd->dialog);
1635 log_printf("The specified folder can not be found: \"%s\"\n", path);
1640 cmd_line = g_strdup_printf("%s --cache-maintenance \"%s\"", gq_executable_path, path);
1642 g_spawn_command_line_async(cmd_line, nullptr);
1645 generic_dialog_close(cd->gd);
1646 cache_manager_sim_reset(cd);
1653 static void cache_manager_cache_maintenance_load_dialog(GtkWidget *widget, const gchar *path)
1659 cd = g_new0(CacheOpsData, 1);
1663 cd->gd = generic_dialog_new(_("Background cache maintenance"), "background_cache_maintenance", widget, FALSE, nullptr, cd);
1664 gtk_window_set_default_size(GTK_WINDOW(cd->gd->dialog), PURGE_DIALOG_WIDTH, -1);
1665 cd->gd->cancel_cb = cache_manager_cache_maintenance_close_cb;
1666 cd->button_close = generic_dialog_add_button(cd->gd, GQ_ICON_CLOSE, _("Close"),
1667 cache_manager_cache_maintenance_close_cb, FALSE);
1668 cd->button_start = generic_dialog_add_button(cd->gd, GQ_ICON_OK, _("S_tart"),
1669 cache_manager_cache_maintenance_start_cb, FALSE);
1671 generic_dialog_add_message(cd->gd, nullptr, _("Recursively delete orphaned thumbnails\nand .sim files, and create new\nthumbnails and .sim files"), nullptr, FALSE);
1673 hbox = pref_box_new(cd->gd->vbox, FALSE, GTK_ORIENTATION_HORIZONTAL, 0);
1674 pref_spacer(hbox, PREF_PAD_INDENT);
1675 cd->group = pref_box_new(hbox, TRUE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
1677 hbox = pref_box_new(cd->group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
1678 pref_label_new(hbox, _("Folder:"));
1680 label = tab_completion_new(&cd->entry, path, nullptr, nullptr, nullptr, nullptr);
1681 tab_completion_add_select_button(cd->entry,_("Select folder") , TRUE);
1682 gq_gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0);
1683 gtk_widget_show(label);
1687 gtk_widget_show(cd->gd->dialog);
1690 static void cache_manager_cache_maintenance_load_cb(GtkWidget *widget, gpointer)
1692 const gchar *path = layout_get_path(nullptr);
1694 if (!path || !*path) path = homedir();
1695 cache_manager_cache_maintenance_load_dialog(widget, path);
1698 void cache_manager_show()
1704 GtkSizeGroup *sizegroup;
1709 gtk_window_present(GTK_WINDOW(cache_manager->dialog->dialog));
1713 cache_manager = g_new0(CacheManager, 1);
1715 cache_manager->dialog = generic_dialog_new(_("Cache Maintenance"),
1718 nullptr, cache_manager);
1719 gd = cache_manager->dialog;
1721 gd->cancel_cb = cache_manager_close_cb;
1722 generic_dialog_add_button(gd, GQ_ICON_CLOSE, _("Close"),
1723 cache_manager_close_cb, FALSE);
1724 generic_dialog_add_button(gd, GQ_ICON_HELP, _("Help"),
1725 cache_manager_help_cb, FALSE);
1727 generic_dialog_add_message(gd, nullptr, _("Cache and Data Maintenance"), nullptr, FALSE);
1729 sizegroup = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
1731 group = pref_group_new(gd->vbox, FALSE, _("Geeqie thumbnail and sim. cache"), GTK_ORIENTATION_VERTICAL);
1733 cache_manager_location_label(group, get_thumbnails_cache_dir());
1735 table = pref_table_new(group, 2, 2, FALSE, FALSE);
1737 button = pref_table_button(table, 0, 0, GQ_ICON_CLEAR, _("Clean up"),
1738 G_CALLBACK(cache_manager_main_clean_cb), cache_manager);
1739 gtk_size_group_add_widget(sizegroup, button);
1740 pref_table_label(table, 1, 0, _("Remove orphaned or outdated thumbnails and sim. files."), GTK_ALIGN_START);
1742 button = pref_table_button(table, 0, 1, GQ_ICON_DELETE, _("Clear cache"),
1743 G_CALLBACK(cache_manager_main_clear_cb), cache_manager);
1744 gtk_size_group_add_widget(sizegroup, button);
1745 pref_table_label(table, 1, 1, _("Delete all cached data."), GTK_ALIGN_START);
1748 group = pref_group_new(gd->vbox, FALSE, _("Shared thumbnail cache"), GTK_ORIENTATION_VERTICAL);
1750 path = g_build_filename(get_thumbnails_standard_cache_dir(), NULL);
1751 cache_manager_location_label(group, path);
1754 table = pref_table_new(group, 2, 2, FALSE, FALSE);
1756 button = pref_table_button(table, 0, 0, GQ_ICON_CLEAR, _("Clean up"),
1757 G_CALLBACK(cache_manager_standard_clean_cb), cache_manager);
1758 gtk_size_group_add_widget(sizegroup, button);
1759 pref_table_label(table, 1, 0, _("Remove orphaned or outdated thumbnails."), GTK_ALIGN_START);
1761 button = pref_table_button(table, 0, 1, GQ_ICON_DELETE, _("Clear cache"),
1762 G_CALLBACK(cache_manager_standard_clear_cb), cache_manager);
1763 gtk_size_group_add_widget(sizegroup, button);
1764 pref_table_label(table, 1, 1, _("Delete all cached thumbnails."), GTK_ALIGN_START);
1766 group = pref_group_new(gd->vbox, FALSE, _("Create thumbnails"), GTK_ORIENTATION_VERTICAL);
1768 table = pref_table_new(group, 2, 1, FALSE, FALSE);
1770 button = pref_table_button(table, 0, 1, GQ_ICON_RUN, _("Render"),
1771 G_CALLBACK(cache_manager_render_cb), cache_manager);
1772 gtk_size_group_add_widget(sizegroup, button);
1773 pref_table_label(table, 1, 1, _("Render thumbnails for a specific folder."), GTK_ALIGN_START);
1774 gtk_widget_set_sensitive(group, options->thumbnails.enable_caching);
1776 group = pref_group_new(gd->vbox, FALSE, _("File similarity cache"), GTK_ORIENTATION_VERTICAL);
1778 table = pref_table_new(group, 3, 2, FALSE, FALSE);
1780 button = pref_table_button(table, 0, 0, GQ_ICON_RUN, _("Create"),
1781 G_CALLBACK(cache_manager_sim_load_cb), cache_manager);
1782 gtk_size_group_add_widget(sizegroup, button);
1783 pref_table_label(table, 1, 0, _("Create sim. files recursively."), GTK_ALIGN_START);
1784 gtk_widget_set_sensitive(group, options->thumbnails.enable_caching);
1786 group = pref_group_new(gd->vbox, FALSE, _("Metadata"), GTK_ORIENTATION_VERTICAL);
1788 cache_manager_location_label(group, get_metadata_cache_dir());
1790 table = pref_table_new(group, 2, 1, FALSE, FALSE);
1792 button = pref_table_button(table, 0, 0, GQ_ICON_CLEAR, _("Clean up"),
1793 G_CALLBACK(cache_manager_metadata_clean_cb), cache_manager);
1794 gtk_size_group_add_widget(sizegroup, button);
1795 pref_table_label(table, 1, 0, _("Remove orphaned keywords and comments."), GTK_ALIGN_START);
1797 group = pref_group_new(gd->vbox, FALSE, _("Background cache maintenance"), GTK_ORIENTATION_VERTICAL);
1799 table = pref_table_new(group, 3, 2, FALSE, FALSE);
1801 button = pref_table_button(table, 0, 0, GQ_ICON_RUN, _("Select"),
1802 G_CALLBACK(cache_manager_cache_maintenance_load_cb), cache_manager);
1803 gtk_size_group_add_widget(sizegroup, button);
1804 pref_table_label(table, 1, 0, _("Run cache maintenance as a background job."), GTK_ALIGN_START);
1805 gtk_widget_set_sensitive(group, options->thumbnails.enable_caching);
1807 gtk_widget_show(cache_manager->dialog->dialog);
1809 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */