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"
25 #include "cache-loader.h"
28 #include "pixbuf-util.h"
30 #include "thumb-standard.h"
31 #include "ui-fileops.h"
33 #include "ui-tabcomp.h"
34 #include "ui-utildlg.h"
42 guint idle_id; /* event source id */
46 GtkWidget *button_stop;
47 GtkWidget *button_close;
53 #define PURGE_DIALOG_WIDTH 400
56 *-----------------------------------------------------------------------------
57 * Command line cache maintenance program functions *-----------------------------------------------------------------------------
59 static gchar *cache_maintenance_path = nullptr;
60 static GtkStatusIcon *status_icon;
62 static void cache_maintenance_sim_stop_cb(gpointer)
67 static void cache_maintenance_render_stop_cb(gpointer)
69 gtk_status_icon_set_tooltip_text(status_icon, _("Geeqie: Creating sim data..."));
70 cache_manager_sim_remote(cache_maintenance_path, TRUE, reinterpret_cast<GDestroyNotify *>(cache_maintenance_sim_stop_cb));
73 static void cache_maintenance_clean_stop_cb(gpointer)
75 gtk_status_icon_set_tooltip_text(status_icon, _("Geeqie: Creating thumbs..."));
76 cache_manager_render_remote(cache_maintenance_path, TRUE, options->thumbnails.cache_into_dirs, reinterpret_cast<GDestroyNotify *>(cache_maintenance_render_stop_cb));
79 static void cache_maintenance_user_cancel_cb()
84 static void cache_maintenance_status_icon_activate_cb(GtkStatusIcon *, gpointer)
89 menu = gtk_menu_new();
91 item = gtk_menu_item_new_with_label(_("Exit Geeqie Cache Maintenance"));
93 g_signal_connect(G_OBJECT(item), "activate", cache_maintenance_user_cancel_cb, item);
94 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
95 gtk_widget_show(item);
97 /* take ownership of menu */
98 g_object_ref_sink(G_OBJECT(menu));
100 gtk_menu_popup_at_pointer(GTK_MENU(menu), nullptr);
103 void cache_maintenance(const gchar *path)
105 cache_maintenance_path = g_strdup(path);
107 status_icon = gtk_status_icon_new_from_pixbuf(pixbuf_inline(PIXBUF_INLINE_ICON));
108 gtk_status_icon_set_tooltip_text(status_icon, _("Geeqie: Cleaning thumbs..."));
109 gtk_status_icon_set_visible(status_icon, TRUE);
110 g_signal_connect(G_OBJECT(status_icon), "activate", G_CALLBACK(cache_maintenance_status_icon_activate_cb), NULL);
112 cache_maintain_home_remote(FALSE, FALSE, reinterpret_cast<GDestroyNotify *>(cache_maintenance_clean_stop_cb));
116 *-------------------------------------------------------------------
118 *-------------------------------------------------------------------
121 static gchar *extension_find_dot(gchar *path)
123 gchar *dot = nullptr;
125 if (!path) return nullptr;
127 while (*path != '\0')
129 if (*path == '.') dot = path;
136 static gboolean isempty(const gchar *path)
142 pathl = path_from_utf8(path);
145 if (!dp) return FALSE;
147 while ((dir = readdir(dp)) != nullptr)
149 gchar *name = dir->d_name;
151 if (name[0] != '.' || (name[1] != '\0' && (name[1] != '.' || name[2] != '\0')) )
162 static void cache_maintain_home_close(CMData *cm)
164 if (cm->idle_id) g_source_remove(cm->idle_id);
165 if (cm->gd) generic_dialog_close(cm->gd);
166 filelist_free(cm->list);
167 g_list_free(cm->done_list);
171 static void cache_maintain_home_stop(CMData *cm)
175 g_source_remove(cm->idle_id);
181 gtk_entry_set_text(GTK_ENTRY(cm->entry), _("done"));
182 gtk_spinner_stop(GTK_SPINNER(cm->spinner));
184 gtk_widget_set_sensitive(cm->button_stop, FALSE);
185 gtk_widget_set_sensitive(cm->button_close, TRUE);
189 static gboolean cache_maintain_home_cb(gpointer data)
191 auto cm = static_cast<CMData *>(data);
192 GList *dlist = nullptr;
193 GList *list = nullptr;
195 gboolean just_done = FALSE;
196 gboolean still_have_a_file = TRUE;
198 const gchar *cache_folder;
199 gboolean filter_disable;
203 cache_folder = get_metadata_cache_dir();
207 cache_folder = get_thumbnails_cache_dir();
210 base_length = strlen(cache_folder);
214 DEBUG_1("purge chk done.");
216 cache_maintain_home_stop(cm);
217 return G_SOURCE_REMOVE;
220 fd = static_cast<FileData *>(cm->list->data);
222 DEBUG_1("purge chk (%d) \"%s\"", (cm->clear && !cm->metadata), fd->path);
225 * It is necessary to disable the file filter when clearing the cache,
226 * otherwise the .sim (file similarity) files are not deleted.
228 filter_disable = options->file_filter.disable;
229 options->file_filter.disable = TRUE;
231 if (g_list_find(cm->done_list, fd) == nullptr)
233 cm->done_list = g_list_prepend(cm->done_list, fd);
235 if (filelist_read(fd, &list, &dlist))
240 still_have_a_file = FALSE;
245 auto fd_list = static_cast<FileData *>(work->data);
246 gchar *path_buf = g_strdup(fd_list->path);
249 dot = extension_find_dot(path_buf);
251 if (dot) *dot = '\0';
252 if ((!cm->metadata && cm->clear) ||
253 (strlen(path_buf) > base_length && !isfile(path_buf + base_length)) )
256 if (!unlink_file(path_buf)) log_printf("failed to delete:%s\n", path_buf);
260 still_have_a_file = TRUE;
267 options->file_filter.disable = filter_disable;
271 cm->list = g_list_concat(dlist, cm->list);
273 if (cm->list && g_list_find(cm->done_list, cm->list->data) != nullptr)
275 /* check if the dir is empty */
277 if (cm->list->data == fd && just_done)
279 if (!still_have_a_file && !dlist && cm->list->next && !rmdir_utf8(fd->path))
281 log_printf("Unable to delete dir: %s\n", fd->path);
286 /* must re-check for an empty dir */
287 if (isempty(fd->path) && cm->list->next && !rmdir_utf8(fd->path))
289 log_printf("Unable to delete dir: %s\n", fd->path);
293 fd = static_cast<FileData *>(cm->list->data);
294 cm->done_list = g_list_remove(cm->done_list, fd);
295 cm->list = g_list_remove(cm->list, fd);
299 if (cm->list && !cm->remote)
303 fd = static_cast<FileData *>(cm->list->data);
304 if (strlen(fd->path) > base_length)
306 buf = fd->path + base_length;
312 gtk_entry_set_text(GTK_ENTRY(cm->entry), buf);
315 return G_SOURCE_CONTINUE;
318 static void cache_maintain_home_close_cb(GenericDialog *, gpointer data)
320 auto cm = static_cast<CMData *>(data);
322 if (!gtk_widget_get_sensitive(cm->button_close)) return;
324 cache_maintain_home_close(cm);
327 static void cache_maintain_home_stop_cb(GenericDialog *, gpointer data)
329 auto cm = static_cast<CMData *>(data);
331 cache_maintain_home_stop(cm);
334 /* sorry for complexity (cm->done_list), but need it to remove empty dirs */
335 void cache_maintain_home(gboolean metadata, gboolean clear, GtkWidget *parent)
341 const gchar *cache_folder;
346 cache_folder = get_metadata_cache_dir();
350 cache_folder = get_thumbnails_cache_dir();
353 dir_fd = file_data_new_dir(cache_folder);
354 if (!filelist_read(dir_fd, nullptr, &dlist))
356 file_data_unref(dir_fd);
360 dlist = g_list_append(dlist, dir_fd);
362 cm = g_new0(CMData, 1);
364 cm->done_list = nullptr;
366 cm->metadata = metadata;
371 msg = _("Removing old metadata...");
375 msg = _("Clearing cached thumbnails...");
379 msg = _("Removing old thumbnails...");
382 cm->gd = generic_dialog_new(_("Maintenance"),
386 cm->gd->cancel_cb = cache_maintain_home_close_cb;
387 cm->button_close = generic_dialog_add_button(cm->gd, GQ_ICON_CLOSE, _("Close"),
388 cache_maintain_home_close_cb, FALSE);
389 gtk_widget_set_sensitive(cm->button_close, FALSE);
390 cm->button_stop = generic_dialog_add_button(cm->gd, GQ_ICON_STOP, _("Stop"),
391 cache_maintain_home_stop_cb, FALSE);
393 generic_dialog_add_message(cm->gd, nullptr, msg, nullptr, FALSE);
394 gtk_window_set_default_size(GTK_WINDOW(cm->gd->dialog), PURGE_DIALOG_WIDTH, -1);
396 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
397 gtk_box_pack_start(GTK_BOX(cm->gd->vbox), hbox, FALSE, FALSE, 5);
398 gtk_widget_show(hbox);
400 cm->entry = gtk_entry_new();
401 gtk_widget_set_can_focus(cm->entry, FALSE);
402 gtk_editable_set_editable(GTK_EDITABLE(cm->entry), FALSE);
403 gtk_box_pack_start(GTK_BOX(hbox), cm->entry, TRUE, TRUE, 0);
404 gtk_widget_show(cm->entry);
406 cm->spinner = gtk_spinner_new();
407 gtk_spinner_start(GTK_SPINNER(cm->spinner));
408 gtk_box_pack_start(GTK_BOX(hbox), cm->spinner, FALSE, FALSE, 0);
409 gtk_widget_show(cm->spinner);
411 gtk_widget_show(cm->gd->dialog);
413 cm->idle_id = g_idle_add(cache_maintain_home_cb, cm);
417 * @brief Clears or culls cached data
418 * @param metadata TRUE - work on metadata cache, FALSE - work on thumbnail cache
419 * @param clear TRUE - clear cache, FALSE - delete orphaned cached items
420 * @param func Function called when idle loop function terminates
424 void cache_maintain_home_remote(gboolean metadata, gboolean clear, GDestroyNotify *func)
429 const gchar *cache_folder;
433 cache_folder = get_metadata_cache_dir();
437 cache_folder = get_thumbnails_cache_dir();
440 dir_fd = file_data_new_dir(cache_folder);
441 if (!filelist_read(dir_fd, nullptr, &dlist))
443 file_data_unref(dir_fd);
447 dlist = g_list_append(dlist, dir_fd);
449 cm = g_new0(CMData, 1);
451 cm->done_list = nullptr;
453 cm->metadata = metadata;
456 cm->idle_id = g_idle_add_full(G_PRIORITY_LOW, cache_maintain_home_cb, cm, reinterpret_cast<GDestroyNotify>(func));
459 static void cache_file_move(const gchar *src, const gchar *dest)
461 if (!dest || !src || !isfile(src)) return;
463 if (!move_file(src, dest))
465 DEBUG_1("Failed to move cache file \"%s\" to \"%s\"", src, dest);
466 /* we remove it anyway - it's stale */
471 static void cache_maint_moved(FileData *fd)
475 const gchar *src = fd->change->source;
476 const gchar *dest = fd->change->dest;
478 if (!src || !dest) return;
480 base = cache_get_location(CACHE_TYPE_THUMB, dest, FALSE, &mode);
481 if (recursive_mkdir_if_not_exists(base, mode))
486 buf = cache_find_location(CACHE_TYPE_THUMB, src);
487 d = cache_get_location(CACHE_TYPE_THUMB, dest, TRUE, nullptr);
488 cache_file_move(buf, d);
492 buf = cache_find_location(CACHE_TYPE_SIM, src);
493 d = cache_get_location(CACHE_TYPE_SIM, dest, TRUE, nullptr);
494 cache_file_move(buf, d);
500 log_printf("Failed to create cache dir for move %s\n", base);
504 base = cache_get_location(CACHE_TYPE_METADATA, dest, FALSE, &mode);
505 if (recursive_mkdir_if_not_exists(base, mode))
510 buf = cache_find_location(CACHE_TYPE_METADATA, src);
511 d = cache_get_location(CACHE_TYPE_METADATA, dest, TRUE, nullptr);
512 cache_file_move(buf, d);
518 if (options->thumbnails.enable_caching && options->thumbnails.spec_standard)
519 thumb_std_maint_moved(src, dest);
522 static void cache_file_remove(const gchar *path)
524 if (path && isfile(path) && !unlink_file(path))
526 DEBUG_1("Failed to remove cache file %s", path);
530 static void cache_maint_removed(FileData *fd)
534 buf = cache_find_location(CACHE_TYPE_THUMB, fd->path);
535 cache_file_remove(buf);
538 buf = cache_find_location(CACHE_TYPE_SIM, fd->path);
539 cache_file_remove(buf);
542 buf = cache_find_location(CACHE_TYPE_METADATA, fd->path);
543 cache_file_remove(buf);
546 if (options->thumbnails.enable_caching && options->thumbnails.spec_standard)
547 thumb_std_maint_removed(fd->path);
550 static void cache_maint_copied(FileData *fd)
556 src_cache = cache_find_location(CACHE_TYPE_METADATA, fd->change->source);
557 if (!src_cache) return;
559 dest_base = cache_get_location(CACHE_TYPE_METADATA, fd->change->dest, FALSE, &mode);
560 if (recursive_mkdir_if_not_exists(dest_base, mode))
564 path = cache_get_location(CACHE_TYPE_METADATA, fd->change->dest, TRUE, nullptr);
565 if (!copy_file(src_cache, path))
567 DEBUG_1("failed to copy metadata %s to %s", src_cache, path);
576 void cache_notify_cb(FileData *fd, NotifyType type, gpointer)
578 if (!(type & NOTIFY_CHANGE) || !fd->change) return;
580 DEBUG_1("Notify cache_maint: %s %04x", fd->path, type);
581 switch (fd->change->type)
583 case FILEDATA_CHANGE_MOVE:
584 case FILEDATA_CHANGE_RENAME:
585 cache_maint_moved(fd);
587 case FILEDATA_CHANGE_COPY:
588 cache_maint_copied(fd);
590 case FILEDATA_CHANGE_DELETE:
591 cache_maint_removed(fd);
593 case FILEDATA_CHANGE_UNSPECIFIED:
594 case FILEDATA_CHANGE_WRITE_METADATA:
601 *-------------------------------------------------------------------
602 * new cache maintenance utilities
603 *-------------------------------------------------------------------
608 GenericDialog *dialog;
609 GtkWidget *folder_entry;
623 GDestroyNotify *destroy_func; /* Used by the command line prog. functions */
631 GtkWidget *button_close;
632 GtkWidget *button_stop;
633 GtkWidget *button_start;
635 GtkWidget *progress_bar;
649 guint idle_id; /* event source id */
652 static void cache_manager_render_reset(CacheOpsData *cd)
654 filelist_free(cd->list);
657 filelist_free(cd->list_dir);
658 cd->list_dir = nullptr;
660 thumb_loader_free(reinterpret_cast<ThumbLoader *>(cd->tl));
664 static void cache_manager_render_close_cb(GenericDialog *, gpointer data)
666 auto cd = static_cast<CacheOpsData *>(data);
668 if (!gtk_widget_get_sensitive(cd->button_close)) return;
670 cache_manager_render_reset(cd);
671 generic_dialog_close(cd->gd);
675 static void cache_manager_render_finish(CacheOpsData *cd)
677 cache_manager_render_reset(cd);
680 gtk_entry_set_text(GTK_ENTRY(cd->progress), _("done"));
681 gtk_spinner_stop(GTK_SPINNER(cd->spinner));
683 gtk_widget_set_sensitive(cd->group, TRUE);
684 gtk_widget_set_sensitive(cd->button_start, TRUE);
685 gtk_widget_set_sensitive(cd->button_stop, FALSE);
686 gtk_widget_set_sensitive(cd->button_close, TRUE);
690 static void cache_manager_render_stop_cb(GenericDialog *, gpointer data)
692 auto cd = static_cast<CacheOpsData *>(data);
694 gtk_entry_set_text(GTK_ENTRY(cd->progress), _("stopped"));
695 cache_manager_render_finish(cd);
698 static void cache_manager_render_folder(CacheOpsData *cd, FileData *dir_fd)
700 GList *list_d = nullptr;
701 GList *list_f = nullptr;
705 filelist_read(dir_fd, &list_f, &list_d);
709 filelist_read(dir_fd, &list_f, nullptr);
712 list_f = filelist_filter(list_f, FALSE);
713 list_d = filelist_filter(list_d, TRUE);
715 cd->list = g_list_concat(list_f, cd->list);
716 cd->list_dir = g_list_concat(list_d, cd->list_dir);
719 static gboolean cache_manager_render_file(CacheOpsData *cd);
721 static void cache_manager_render_thumb_done_cb(ThumbLoader *, gpointer data)
723 auto cd = static_cast<CacheOpsData *>(data);
725 thumb_loader_free(reinterpret_cast<ThumbLoader *>(cd->tl));
728 while (cache_manager_render_file(cd));
731 static gboolean cache_manager_render_file(CacheOpsData *cd)
738 fd = static_cast<FileData *>(cd->list->data);
739 cd->list = g_list_remove(cd->list, fd);
741 cd->tl = reinterpret_cast<ThumbLoaderStd *>(thumb_loader_new(options->thumbnails.max_width, options->thumbnails.max_height));
742 thumb_loader_set_callbacks(reinterpret_cast<ThumbLoader *>(cd->tl),
743 cache_manager_render_thumb_done_cb,
744 cache_manager_render_thumb_done_cb,
746 thumb_loader_set_cache(reinterpret_cast<ThumbLoader *>(cd->tl), TRUE, cd->local, TRUE);
747 success = thumb_loader_start(reinterpret_cast<ThumbLoader *>(cd->tl), fd);
752 gtk_entry_set_text(GTK_ENTRY(cd->progress), fd->path);
753 cd->count_done = cd->count_done + 1;
754 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(cd->progress_bar), static_cast<gdouble>(cd->count_done) / cd->count_total);
759 thumb_loader_free(reinterpret_cast<ThumbLoader *>(cd->tl));
767 else if (cd->list_dir)
771 fd = static_cast<FileData *>(cd->list_dir->data);
772 cd->list_dir = g_list_remove(cd->list_dir, fd);
774 cache_manager_render_folder(cd, fd);
783 gtk_entry_set_text(GTK_ENTRY(cd->progress), _("done"));
785 cache_manager_render_finish(cd);
787 if (cd->destroy_func)
789 g_idle_add(reinterpret_cast<GSourceFunc>(cd->destroy_func), nullptr);
795 static void cache_manager_render_start_cb(GenericDialog *, gpointer data)
797 auto cd = static_cast<CacheOpsData *>(data);
799 GList *list_total = nullptr;
803 if (cd->list || !gtk_widget_get_sensitive(cd->button_start)) return;
806 path = remove_trailing_slash((gtk_entry_get_text(GTK_ENTRY(cd->entry))));
807 parse_out_relatives(path);
813 warning_dialog(_("Invalid folder"),
814 _("The specified folder can not be found."),
815 GQ_ICON_DIALOG_WARNING, cd->gd->dialog);
819 log_printf("The specified folder can not be found: %s\n", path);
827 gtk_widget_set_sensitive(cd->group, FALSE);
828 gtk_widget_set_sensitive(cd->button_start, FALSE);
829 gtk_widget_set_sensitive(cd->button_stop, TRUE);
830 gtk_widget_set_sensitive(cd->button_close, FALSE);
832 gtk_spinner_start(GTK_SPINNER(cd->spinner));
834 dir_fd = file_data_new_dir(path);
835 cache_manager_render_folder(cd, dir_fd);
836 list_total = filelist_recursive(dir_fd);
837 cd->count_total = g_list_length(list_total);
838 file_data_unref(dir_fd);
839 g_list_free(list_total);
842 while (cache_manager_render_file(cd));
848 static void cache_manager_render_start_render_remote(CacheOpsData *cd, const gchar *user_path)
852 path = remove_trailing_slash(user_path);
853 parse_out_relatives(path);
857 log_printf("The specified folder can not be found: %s\n", path);
863 dir_fd = file_data_new_dir(path);
864 cache_manager_render_folder(cd, dir_fd);
865 file_data_unref(dir_fd);
866 while (cache_manager_render_file(cd));
872 static void cache_manager_render_dialog(GtkWidget *widget, const gchar *path)
879 cd = g_new0(CacheOpsData, 1);
882 cd->gd = generic_dialog_new(_("Create thumbnails"),
886 gtk_window_set_default_size(GTK_WINDOW(cd->gd->dialog), PURGE_DIALOG_WIDTH, -1);
887 cd->gd->cancel_cb = cache_manager_render_close_cb;
888 cd->button_close = generic_dialog_add_button(cd->gd, GQ_ICON_CLOSE, _("Close"),
889 cache_manager_render_close_cb, FALSE);
890 cd->button_start = generic_dialog_add_button(cd->gd, GQ_ICON_OK, _("S_tart"),
891 cache_manager_render_start_cb, FALSE);
892 cd->button_stop = generic_dialog_add_button(cd->gd, GQ_ICON_STOP, _("Stop"),
893 cache_manager_render_stop_cb, FALSE);
894 gtk_widget_set_sensitive(cd->button_stop, FALSE);
896 generic_dialog_add_message(cd->gd, nullptr, _("Create thumbnails"), nullptr, FALSE);
898 hbox = pref_box_new(cd->gd->vbox, FALSE, GTK_ORIENTATION_HORIZONTAL, 0);
899 pref_spacer(hbox, PREF_PAD_INDENT);
900 cd->group = pref_box_new(hbox, TRUE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
902 hbox = pref_box_new(cd->group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
903 pref_label_new(hbox, _("Folder:"));
905 label = tab_completion_new(&cd->entry, path, nullptr, nullptr, nullptr, nullptr);
906 tab_completion_add_select_button(cd->entry,_("Select folder") , TRUE);
907 gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0);
908 gtk_widget_show(label);
910 pref_checkbox_new_int(cd->group, _("Include subfolders"), FALSE, &cd->recurse);
911 button = pref_checkbox_new_int(cd->group, _("Store thumbnails local to source images"), FALSE, &cd->local);
912 gtk_widget_set_sensitive(button, options->thumbnails.spec_standard);
914 pref_line(cd->gd->vbox, PREF_PAD_SPACE);
915 hbox = pref_box_new(cd->gd->vbox, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
917 cd->progress = gtk_entry_new();
918 gtk_widget_set_can_focus(cd->progress, FALSE);
919 gtk_editable_set_editable(GTK_EDITABLE(cd->progress), FALSE);
920 gtk_entry_set_text(GTK_ENTRY(cd->progress), _("click start to begin"));
921 gtk_box_pack_start(GTK_BOX(hbox), cd->progress, TRUE, TRUE, 0);
922 gtk_widget_show(cd->progress);
924 cd->progress_bar = gtk_progress_bar_new();
925 gtk_box_pack_start(GTK_BOX(cd->gd->vbox), cd->progress_bar, TRUE, TRUE, 0);
926 gtk_widget_show(cd->progress_bar);
928 cd->spinner = gtk_spinner_new();
929 gtk_box_pack_start(GTK_BOX(hbox), cd->spinner, FALSE, FALSE, 0);
930 gtk_widget_show(cd->spinner);
934 gtk_widget_show(cd->gd->dialog);
938 * @brief Create thumbnails
939 * @param path Path to image folder
941 * @param local Create thumbnails in same folder as images
942 * @param func Function called when idle loop function terminates
946 void cache_manager_render_remote(const gchar *path, gboolean recurse, gboolean local, GDestroyNotify *func)
950 cd = g_new0(CacheOpsData, 1);
951 cd->recurse = recurse;
954 cd->destroy_func = func;
956 cache_manager_render_start_render_remote(cd, path);
959 static void cache_manager_standard_clean_close_cb(GenericDialog *, gpointer data)
961 auto cd = static_cast<CacheOpsData *>(data);
963 if (!gtk_widget_get_sensitive(cd->button_close)) return;
965 generic_dialog_close(cd->gd);
967 thumb_loader_std_thumb_file_validate_cancel(cd->tl);
968 filelist_free(cd->list);
972 static void cache_manager_standard_clean_done(CacheOpsData *cd)
976 gtk_widget_set_sensitive(cd->button_stop, FALSE);
977 gtk_widget_set_sensitive(cd->button_close, TRUE);
979 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(cd->progress), 1.0);
980 gtk_progress_bar_set_text(GTK_PROGRESS_BAR(cd->progress), _("done"));
984 g_source_remove(cd->idle_id);
988 thumb_loader_std_thumb_file_validate_cancel(cd->tl);
991 filelist_free(cd->list);
995 static void cache_manager_standard_clean_stop_cb(GenericDialog *, gpointer data)
997 auto cd = static_cast<CacheOpsData *>(data);
999 cache_manager_standard_clean_done(cd);
1002 static gint cache_manager_standard_clean_clear_cb(gpointer data)
1004 auto cd = static_cast<CacheOpsData *>(data);
1010 next_fd = static_cast<FileData *>(cd->list->data);
1011 cd->list = g_list_remove(cd->list, next_fd);
1013 DEBUG_1("thumb removed: %s", next_fd->path);
1015 unlink_file(next_fd->path);
1016 file_data_unref(next_fd);
1021 if (cd->count_total != 0)
1023 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(cd->progress),
1024 static_cast<gdouble>(cd->count_done) / cd->count_total);
1028 return G_SOURCE_CONTINUE;
1032 cache_manager_standard_clean_done(cd);
1033 return G_SOURCE_REMOVE;
1036 static void cache_manager_standard_clean_valid_cb(const gchar *path, gboolean valid, gpointer data)
1038 auto cd = static_cast<CacheOpsData *>(data);
1044 DEBUG_1("thumb cleaned: %s", path);
1051 if (cd->count_total != 0)
1053 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(cd->progress),
1054 static_cast<gdouble>(cd->count_done) / cd->count_total);
1064 next_fd = static_cast<FileData *>(cd->list->data);
1065 cd->list = g_list_remove(cd->list, next_fd);
1067 cd->tl = thumb_loader_std_thumb_file_validate(next_fd->path, cd->days,
1068 cache_manager_standard_clean_valid_cb, cd);
1069 file_data_unref(next_fd);
1073 cache_manager_standard_clean_done(cd);
1077 static void cache_manager_standard_clean_start(GenericDialog *, gpointer data)
1079 auto cd = static_cast<CacheOpsData *>(data);
1086 if (cd->list || !gtk_widget_get_sensitive(cd->button_start)) return;
1088 gtk_widget_set_sensitive(cd->button_start, FALSE);
1089 gtk_widget_set_sensitive(cd->button_stop, TRUE);
1090 gtk_widget_set_sensitive(cd->button_close, FALSE);
1092 gtk_progress_bar_set_text(GTK_PROGRESS_BAR(cd->progress), _("running..."));
1095 path = g_build_filename(get_thumbnails_standard_cache_dir(), THUMB_FOLDER_NORMAL, NULL);
1096 dir_fd = file_data_new_dir(path);
1097 filelist_read(dir_fd, &list, nullptr);
1099 file_data_unref(dir_fd);
1102 path = g_build_filename(get_thumbnails_standard_cache_dir(), THUMB_FOLDER_LARGE, NULL);
1103 dir_fd = file_data_new_dir(path);
1104 filelist_read(dir_fd, &list, nullptr);
1105 cd->list = g_list_concat(cd->list, list);
1106 file_data_unref(dir_fd);
1109 path = g_build_filename(get_thumbnails_standard_cache_dir(), THUMB_FOLDER_FAIL, NULL);
1110 dir_fd = file_data_new_dir(path);
1111 filelist_read(dir_fd, &list, nullptr);
1112 cd->list = g_list_concat(cd->list, list);
1113 file_data_unref(dir_fd);
1116 cd->count_total = g_list_length(cd->list);
1119 /* start iterating */
1122 cd->idle_id = g_idle_add(cache_manager_standard_clean_clear_cb, cd);
1126 cache_manager_standard_clean_valid_cb(nullptr, TRUE, cd);
1130 static void cache_manager_standard_clean_start_cb(GenericDialog *gd, gpointer data)
1132 cache_manager_standard_clean_start(gd, data);
1135 static void cache_manager_standard_process(GtkWidget *widget, gboolean clear)
1138 const gchar *icon_name;
1141 cd = g_new0(CacheOpsData, 1);
1147 icon_name = GQ_ICON_DELETE;
1148 msg = _("Clearing thumbnails...");
1152 icon_name = GQ_ICON_CLEAR;
1153 msg = _("Removing old thumbnails...");
1156 cd->gd = generic_dialog_new(_("Maintenance"),
1157 "standard_maintenance",
1160 cd->gd->cancel_cb = cache_manager_standard_clean_close_cb;
1161 cd->button_close = generic_dialog_add_button(cd->gd, GQ_ICON_CLOSE, _("Close"),
1162 cache_manager_standard_clean_close_cb, FALSE);
1163 cd->button_start = generic_dialog_add_button(cd->gd, GQ_ICON_OK, _("S_tart"),
1164 cache_manager_standard_clean_start_cb, FALSE);
1165 cd->button_stop = generic_dialog_add_button(cd->gd, GQ_ICON_STOP, _("Stop"),
1166 cache_manager_standard_clean_stop_cb, FALSE);
1167 gtk_widget_set_sensitive(cd->button_stop, FALSE);
1169 generic_dialog_add_message(cd->gd, icon_name, msg, NULL, FALSE);
1171 cd->progress = gtk_progress_bar_new();
1172 gtk_progress_bar_set_text(GTK_PROGRESS_BAR(cd->progress), _("click start to begin"));
1173 gtk_progress_bar_set_show_text(GTK_PROGRESS_BAR(cd->progress), TRUE);
1174 gtk_box_pack_start(GTK_BOX(cd->gd->vbox), cd->progress, FALSE, FALSE, 0);
1175 gtk_widget_show(cd->progress);
1181 gtk_widget_show(cd->gd->dialog);
1184 void cache_manager_standard_process_remote(gboolean clear)
1188 cd = g_new0(CacheOpsData, 1);
1195 cache_manager_standard_clean_start(nullptr, cd);
1198 static void cache_manager_standard_clean_cb(GtkWidget *widget, gpointer)
1200 cache_manager_standard_process(widget, FALSE);
1203 static void cache_manager_standard_clear_cb(GtkWidget *widget, gpointer)
1205 cache_manager_standard_process(widget, TRUE);
1209 static void cache_manager_main_clean_cb(GtkWidget *widget, gpointer)
1211 cache_maintain_home(FALSE, FALSE, widget);
1215 static void dummy_cancel_cb(GenericDialog *, gpointer)
1217 /* no op, only so cancel button appears */
1220 static void cache_manager_main_clear_ok_cb(GenericDialog *, gpointer)
1222 cache_maintain_home(FALSE, TRUE, nullptr);
1225 void cache_manager_main_clear_confirm(GtkWidget *parent)
1229 gd = generic_dialog_new(_("Clear cache"),
1230 "clear_cache", parent, TRUE,
1231 dummy_cancel_cb, nullptr);
1232 generic_dialog_add_message(gd, GQ_ICON_DIALOG_QUESTION, _("Clear cache"),
1233 _("This will remove all thumbnails and sim. files\nthat have been saved to disk, continue?"), TRUE);
1234 generic_dialog_add_button(gd, GQ_ICON_OK, "OK", cache_manager_main_clear_ok_cb, TRUE);
1236 gtk_widget_show(gd->dialog);
1239 static void cache_manager_main_clear_cb(GtkWidget *widget, gpointer)
1241 cache_manager_main_clear_confirm(widget);
1244 static void cache_manager_render_cb(GtkWidget *widget, gpointer)
1246 const gchar *path = layout_get_path(nullptr);
1248 if (!path || !*path) path = homedir();
1249 cache_manager_render_dialog(widget, path);
1252 static void cache_manager_metadata_clean_cb(GtkWidget *widget, gpointer)
1254 cache_maintain_home(TRUE, FALSE, widget);
1258 static CacheManager *cache_manager = nullptr;
1260 static void cache_manager_close_cb(GenericDialog *gd, gpointer)
1262 generic_dialog_close(gd);
1264 g_free(cache_manager);
1265 cache_manager = nullptr;
1268 static void cache_manager_help_cb(GenericDialog *, gpointer)
1270 help_window_show("GuideReferenceManagement.html");
1273 static GtkWidget *cache_manager_location_label(GtkWidget *group, const gchar *subdir)
1278 buf = g_strdup_printf(_("Location: %s"), subdir);
1279 label = pref_label_new(group, buf);
1281 gtk_label_set_xalign(GTK_LABEL(label), 0.0);
1282 gtk_label_set_yalign(GTK_LABEL(label), 0.5);
1287 static gboolean cache_manager_sim_file(CacheOpsData *cd);
1289 static void cache_manager_sim_reset(CacheOpsData *cd)
1291 filelist_free(cd->list);
1294 filelist_free(cd->list_dir);
1295 cd->list_dir = nullptr;
1297 cache_loader_free(cd->cl);
1301 static void cache_manager_sim_close_cb(GenericDialog *, gpointer data)
1303 auto cd = static_cast<CacheOpsData *>(data);
1305 if (!gtk_widget_get_sensitive(cd->button_close)) return;
1307 cache_manager_sim_reset(cd);
1308 generic_dialog_close(cd->gd);
1312 static void cache_manager_sim_finish(CacheOpsData *cd)
1314 cache_manager_sim_reset(cd);
1317 gtk_spinner_stop(GTK_SPINNER(cd->spinner));
1319 gtk_widget_set_sensitive(cd->group, TRUE);
1320 gtk_widget_set_sensitive(cd->button_start, TRUE);
1321 gtk_widget_set_sensitive(cd->button_stop, FALSE);
1322 gtk_widget_set_sensitive(cd->button_close, TRUE);
1326 static void cache_manager_sim_stop_cb(GenericDialog *, gpointer data)
1328 auto cd = static_cast<CacheOpsData *>(data);
1330 gtk_entry_set_text(GTK_ENTRY(cd->progress), _("stopped"));
1331 cache_manager_sim_finish(cd);
1334 static void cache_manager_sim_folder(CacheOpsData *cd, FileData *dir_fd)
1336 GList *list_d = nullptr;
1337 GList *list_f = nullptr;
1341 filelist_read(dir_fd, &list_f, &list_d);
1345 filelist_read(dir_fd, &list_f, nullptr);
1348 list_f = filelist_filter(list_f, FALSE);
1349 list_d = filelist_filter(list_d, TRUE);
1351 cd->list = g_list_concat(list_f, cd->list);
1352 cd->list_dir = g_list_concat(list_d, cd->list_dir);
1355 static void cache_manager_sim_file_done_cb(CacheLoader *, gint, gpointer data)
1357 auto cd = static_cast<CacheOpsData *>(data);
1359 cache_loader_free(cd->cl);
1362 while (cache_manager_sim_file(cd));
1365 static void cache_manager_sim_start_sim_remote(CacheOpsData *cd, const gchar *user_path)
1369 path = remove_trailing_slash(user_path);
1370 parse_out_relatives(path);
1374 log_printf("The specified folder can not be found: %s\n", path);
1380 dir_fd = file_data_new_dir(path);
1381 cache_manager_sim_folder(cd, dir_fd);
1382 file_data_unref(dir_fd);
1383 while (cache_manager_sim_file(cd));
1390 * @brief Generate .sim files
1391 * @param path Path to image folder
1393 * @param func Function called when idle loop function terminates
1397 void cache_manager_sim_remote(const gchar *path, gboolean recurse, GDestroyNotify *func)
1401 cd = g_new0(CacheOpsData, 1);
1402 cd->recurse = recurse;
1404 cd->destroy_func = func;
1406 cache_manager_sim_start_sim_remote(cd, path);
1409 static gboolean cache_manager_sim_file(CacheOpsData *cd)
1411 CacheDataType load_mask;
1416 fd = static_cast<FileData *>(cd->list->data);
1417 cd->list = g_list_remove(cd->list, fd);
1419 load_mask = static_cast<CacheDataType>(CACHE_LOADER_DIMENSIONS | CACHE_LOADER_DATE | CACHE_LOADER_MD5SUM | CACHE_LOADER_SIMILARITY);
1420 cd->cl = cache_loader_new(fd, load_mask, (cache_manager_sim_file_done_cb), cd);
1424 gtk_entry_set_text(GTK_ENTRY(cd->progress), fd->path);
1427 file_data_unref(fd);
1428 cd->count_done = cd->count_done + 1;
1431 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(cd->progress_bar), static_cast<gdouble>(cd->count_done) / cd->count_total);
1436 else if (cd->list_dir)
1440 fd = static_cast<FileData *>(cd->list_dir->data);
1441 cd->list_dir = g_list_remove(cd->list_dir, fd);
1443 cache_manager_sim_folder(cd, fd);
1444 file_data_unref(fd);
1451 gtk_entry_set_text(GTK_ENTRY(cd->progress), _("done"));
1454 cache_manager_sim_finish(cd);
1456 if (cd->destroy_func)
1458 g_idle_add(reinterpret_cast<GSourceFunc>(cd->destroy_func), nullptr);
1464 static void cache_manager_sim_start_cb(GenericDialog *, gpointer data)
1466 auto cd = static_cast<CacheOpsData *>(data);
1468 GList *list_total = nullptr;
1472 if (cd->list || !gtk_widget_get_sensitive(cd->button_start)) return;
1475 path = remove_trailing_slash((gtk_entry_get_text(GTK_ENTRY(cd->entry))));
1476 parse_out_relatives(path);
1482 warning_dialog(_("Invalid folder"),
1483 _("The specified folder can not be found."),
1484 GQ_ICON_DIALOG_WARNING, cd->gd->dialog);
1488 log_printf("The specified folder can not be found: %s\n", path);
1496 gtk_widget_set_sensitive(cd->group, FALSE);
1497 gtk_widget_set_sensitive(cd->button_start, FALSE);
1498 gtk_widget_set_sensitive(cd->button_stop, TRUE);
1499 gtk_widget_set_sensitive(cd->button_close, FALSE);
1501 gtk_spinner_start(GTK_SPINNER(cd->spinner));
1503 dir_fd = file_data_new_dir(path);
1504 cache_manager_sim_folder(cd, dir_fd);
1505 list_total = filelist_recursive(dir_fd);
1506 cd->count_total = g_list_length(list_total);
1507 file_data_unref(dir_fd);
1508 g_list_free(list_total);
1511 while (cache_manager_sim_file(static_cast<CacheOpsData *>(cd)));
1517 static void cache_manager_sim_load_dialog(GtkWidget *widget, const gchar *path)
1523 cd = g_new0(CacheOpsData, 1);
1527 cd->gd = generic_dialog_new(_("Create sim. files"), "create_sim_files", widget, FALSE, nullptr, cd);
1528 gtk_window_set_default_size(GTK_WINDOW(cd->gd->dialog), PURGE_DIALOG_WIDTH, -1);
1529 cd->gd->cancel_cb = cache_manager_sim_close_cb;
1530 cd->button_close = generic_dialog_add_button(cd->gd, GQ_ICON_CLOSE, _("Close"),
1531 cache_manager_sim_close_cb, FALSE);
1532 cd->button_start = generic_dialog_add_button(cd->gd, GQ_ICON_OK, _("S_tart"),
1533 cache_manager_sim_start_cb, FALSE);
1534 cd->button_stop = generic_dialog_add_button(cd->gd, GQ_ICON_STOP, _("Stop"),
1535 cache_manager_sim_stop_cb, FALSE);
1536 gtk_widget_set_sensitive(cd->button_stop, FALSE);
1538 generic_dialog_add_message(cd->gd, nullptr, _("Create sim. files recursively"), nullptr, FALSE);
1540 hbox = pref_box_new(cd->gd->vbox, FALSE, GTK_ORIENTATION_HORIZONTAL, 0);
1541 pref_spacer(hbox, PREF_PAD_INDENT);
1542 cd->group = pref_box_new(hbox, TRUE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
1544 hbox = pref_box_new(cd->group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
1545 pref_label_new(hbox, _("Folder:"));
1547 label = tab_completion_new(&cd->entry, path, nullptr, nullptr, nullptr, nullptr);
1548 tab_completion_add_select_button(cd->entry,_("Select folder") , TRUE);
1549 gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0);
1550 gtk_widget_show(label);
1552 pref_line(cd->gd->vbox, PREF_PAD_SPACE);
1553 hbox = pref_box_new(cd->gd->vbox, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
1555 cd->progress = gtk_entry_new();
1556 gtk_widget_set_can_focus(cd->progress, FALSE);
1557 gtk_editable_set_editable(GTK_EDITABLE(cd->progress), FALSE);
1558 gtk_entry_set_text(GTK_ENTRY(cd->progress), _("click start to begin"));
1559 gtk_box_pack_start(GTK_BOX(hbox), cd->progress, TRUE, TRUE, 0);
1560 gtk_widget_show(cd->progress);
1562 cd->progress_bar = gtk_progress_bar_new();
1563 gtk_box_pack_start(GTK_BOX(cd->gd->vbox), cd->progress_bar, TRUE, TRUE, 0);
1564 gtk_widget_show(cd->progress_bar);
1566 cd->spinner = gtk_spinner_new();
1567 gtk_box_pack_start(GTK_BOX(hbox), cd->spinner, FALSE, FALSE, 0);
1568 gtk_widget_show(cd->spinner);
1572 gtk_widget_show(cd->gd->dialog);
1575 static void cache_manager_sim_load_cb(GtkWidget *widget, gpointer)
1577 const gchar *path = layout_get_path(nullptr);
1579 if (!path || !*path) path = homedir();
1580 cache_manager_sim_load_dialog(widget, path);
1583 static void cache_manager_cache_maintenance_close_cb(GenericDialog *, gpointer data)
1585 auto cd = static_cast<CacheOpsData *>(data);
1587 if (!gtk_widget_get_sensitive(cd->button_close)) return;
1589 cache_manager_sim_reset(cd);
1590 generic_dialog_close(cd->gd);
1594 static void cache_manager_cache_maintenance_start_cb(GenericDialog *, gpointer data)
1596 auto cd = static_cast<CacheOpsData *>(data);
1602 if (cd->list || !gtk_widget_get_sensitive(cd->button_start)) return;
1605 path = remove_trailing_slash((gtk_entry_get_text(GTK_ENTRY(cd->entry))));
1606 parse_out_relatives(path);
1612 warning_dialog(_("Invalid folder"),
1613 _("The specified folder can not be found."),
1614 GQ_ICON_DIALOG_WARNING, cd->gd->dialog);
1618 log_printf("The specified folder can not be found: \"%s\"\n", path);
1623 cmd_line = g_strdup_printf("%s --cache-maintenance \"%s\"", gq_executable_path, path);
1625 g_spawn_command_line_async(cmd_line, nullptr);
1628 generic_dialog_close(cd->gd);
1629 cache_manager_sim_reset(cd);
1636 static void cache_manager_cache_maintenance_load_dialog(GtkWidget *widget, const gchar *path)
1642 cd = g_new0(CacheOpsData, 1);
1646 cd->gd = generic_dialog_new(_("Background cache maintenance"), "background_cache_maintenance", widget, FALSE, nullptr, cd);
1647 gtk_window_set_default_size(GTK_WINDOW(cd->gd->dialog), PURGE_DIALOG_WIDTH, -1);
1648 cd->gd->cancel_cb = cache_manager_cache_maintenance_close_cb;
1649 cd->button_close = generic_dialog_add_button(cd->gd, GQ_ICON_CLOSE, _("Close"),
1650 cache_manager_cache_maintenance_close_cb, FALSE);
1651 cd->button_start = generic_dialog_add_button(cd->gd, GQ_ICON_OK, _("S_tart"),
1652 cache_manager_cache_maintenance_start_cb, FALSE);
1654 generic_dialog_add_message(cd->gd, nullptr, _("Recursively delete orphaned thumbnails\nand .sim files, and create new\nthumbnails and .sim files"), nullptr, FALSE);
1656 hbox = pref_box_new(cd->gd->vbox, FALSE, GTK_ORIENTATION_HORIZONTAL, 0);
1657 pref_spacer(hbox, PREF_PAD_INDENT);
1658 cd->group = pref_box_new(hbox, TRUE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
1660 hbox = pref_box_new(cd->group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
1661 pref_label_new(hbox, _("Folder:"));
1663 label = tab_completion_new(&cd->entry, path, nullptr, nullptr, nullptr, nullptr);
1664 tab_completion_add_select_button(cd->entry,_("Select folder") , TRUE);
1665 gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0);
1666 gtk_widget_show(label);
1670 gtk_widget_show(cd->gd->dialog);
1673 static void cache_manager_cache_maintenance_load_cb(GtkWidget *widget, gpointer)
1675 const gchar *path = layout_get_path(nullptr);
1677 if (!path || !*path) path = homedir();
1678 cache_manager_cache_maintenance_load_dialog(widget, path);
1681 void cache_manager_show()
1687 GtkSizeGroup *sizegroup;
1692 gtk_window_present(GTK_WINDOW(cache_manager->dialog->dialog));
1696 cache_manager = g_new0(CacheManager, 1);
1698 cache_manager->dialog = generic_dialog_new(_("Cache Maintenance"),
1701 nullptr, cache_manager);
1702 gd = cache_manager->dialog;
1704 gd->cancel_cb = cache_manager_close_cb;
1705 generic_dialog_add_button(gd, GQ_ICON_CLOSE, _("Close"),
1706 cache_manager_close_cb, FALSE);
1707 generic_dialog_add_button(gd, GQ_ICON_HELP, _("Help"),
1708 cache_manager_help_cb, FALSE);
1710 generic_dialog_add_message(gd, nullptr, _("Cache and Data Maintenance"), nullptr, FALSE);
1712 sizegroup = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
1714 group = pref_group_new(gd->vbox, FALSE, _("Geeqie thumbnail and sim. cache"), GTK_ORIENTATION_VERTICAL);
1716 cache_manager_location_label(group, get_thumbnails_cache_dir());
1718 table = pref_table_new(group, 2, 2, FALSE, FALSE);
1720 button = pref_table_button(table, 0, 0, GQ_ICON_CLEAR, _("Clean up"),
1721 G_CALLBACK(cache_manager_main_clean_cb), cache_manager);
1722 gtk_size_group_add_widget(sizegroup, button);
1723 pref_table_label(table, 1, 0, _("Remove orphaned or outdated thumbnails and sim. files."), GTK_ALIGN_START);
1725 button = pref_table_button(table, 0, 1, GQ_ICON_DELETE, _("Clear cache"),
1726 G_CALLBACK(cache_manager_main_clear_cb), cache_manager);
1727 gtk_size_group_add_widget(sizegroup, button);
1728 pref_table_label(table, 1, 1, _("Delete all cached data."), GTK_ALIGN_START);
1731 group = pref_group_new(gd->vbox, FALSE, _("Shared thumbnail cache"), GTK_ORIENTATION_VERTICAL);
1733 path = g_build_filename(get_thumbnails_standard_cache_dir(), NULL);
1734 cache_manager_location_label(group, path);
1737 table = pref_table_new(group, 2, 2, FALSE, FALSE);
1739 button = pref_table_button(table, 0, 0, GQ_ICON_CLEAR, _("Clean up"),
1740 G_CALLBACK(cache_manager_standard_clean_cb), cache_manager);
1741 gtk_size_group_add_widget(sizegroup, button);
1742 pref_table_label(table, 1, 0, _("Remove orphaned or outdated thumbnails."), GTK_ALIGN_START);
1744 button = pref_table_button(table, 0, 1, GQ_ICON_DELETE, _("Clear cache"),
1745 G_CALLBACK(cache_manager_standard_clear_cb), cache_manager);
1746 gtk_size_group_add_widget(sizegroup, button);
1747 pref_table_label(table, 1, 1, _("Delete all cached thumbnails."), GTK_ALIGN_START);
1749 group = pref_group_new(gd->vbox, FALSE, _("Create thumbnails"), GTK_ORIENTATION_VERTICAL);
1751 table = pref_table_new(group, 2, 1, FALSE, FALSE);
1753 button = pref_table_button(table, 0, 1, GQ_ICON_RUN, _("Render"),
1754 G_CALLBACK(cache_manager_render_cb), cache_manager);
1755 gtk_size_group_add_widget(sizegroup, button);
1756 pref_table_label(table, 1, 1, _("Render thumbnails for a specific folder."), GTK_ALIGN_START);
1757 gtk_widget_set_sensitive(group, options->thumbnails.enable_caching);
1759 group = pref_group_new(gd->vbox, FALSE, _("File similarity cache"), GTK_ORIENTATION_VERTICAL);
1761 table = pref_table_new(group, 3, 2, FALSE, FALSE);
1763 button = pref_table_button(table, 0, 0, GQ_ICON_RUN, _("Create"),
1764 G_CALLBACK(cache_manager_sim_load_cb), cache_manager);
1765 gtk_size_group_add_widget(sizegroup, button);
1766 pref_table_label(table, 1, 0, _("Create sim. files recursively."), GTK_ALIGN_START);
1767 gtk_widget_set_sensitive(group, options->thumbnails.enable_caching);
1769 group = pref_group_new(gd->vbox, FALSE, _("Metadata"), GTK_ORIENTATION_VERTICAL);
1771 cache_manager_location_label(group, get_metadata_cache_dir());
1773 table = pref_table_new(group, 2, 1, FALSE, FALSE);
1775 button = pref_table_button(table, 0, 0, GQ_ICON_CLEAR, _("Clean up"),
1776 G_CALLBACK(cache_manager_metadata_clean_cb), cache_manager);
1777 gtk_size_group_add_widget(sizegroup, button);
1778 pref_table_label(table, 1, 0, _("Remove orphaned keywords and comments."), GTK_ALIGN_START);
1780 group = pref_group_new(gd->vbox, FALSE, _("Background cache maintenance"), GTK_ORIENTATION_VERTICAL);
1782 table = pref_table_new(group, 3, 2, FALSE, FALSE);
1784 button = pref_table_button(table, 0, 0, GQ_ICON_RUN, _("Select"),
1785 G_CALLBACK(cache_manager_cache_maintenance_load_cb), cache_manager);
1786 gtk_size_group_add_widget(sizegroup, button);
1787 pref_table_label(table, 1, 0, _("Run cache maintenance as a background job."), GTK_ALIGN_START);
1788 gtk_widget_set_sensitive(group, options->thumbnails.enable_caching);
1790 gtk_widget_show(cache_manager->dialog->dialog);
1792 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */