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"
55 constexpr gint PURGE_DIALOG_WIDTH = 400;
63 guint idle_id; /* event source id */
67 GtkWidget *button_stop;
68 GtkWidget *button_close;
75 *-----------------------------------------------------------------------------
76 * Command line cache maintenance program functions *-----------------------------------------------------------------------------
78 static gchar *cache_maintenance_path = nullptr;
79 static GtkStatusIcon *status_icon;
81 static void cache_maintenance_sim_stop_cb(gpointer)
86 static void cache_maintenance_render_stop_cb(gpointer)
88 gtk_status_icon_set_tooltip_text(status_icon, _("Geeqie: Creating sim data..."));
89 cache_manager_sim_remote(cache_maintenance_path, TRUE, reinterpret_cast<GDestroyNotify *>(cache_maintenance_sim_stop_cb));
92 static void cache_maintenance_clean_stop_cb(gpointer)
94 gtk_status_icon_set_tooltip_text(status_icon, _("Geeqie: Creating thumbs..."));
95 cache_manager_render_remote(cache_maintenance_path, TRUE, options->thumbnails.cache_into_dirs, reinterpret_cast<GDestroyNotify *>(cache_maintenance_render_stop_cb));
98 static void cache_maintenance_user_cancel_cb()
103 static void cache_maintenance_status_icon_activate_cb(GtkStatusIcon *, gpointer)
108 menu = gtk_menu_new();
110 item = gtk_menu_item_new_with_label(_("Exit Geeqie Cache Maintenance"));
112 g_signal_connect(G_OBJECT(item), "activate", cache_maintenance_user_cancel_cb, item);
113 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
114 gtk_widget_show(item);
116 /* take ownership of menu */
117 g_object_ref_sink(G_OBJECT(menu));
119 gtk_menu_popup_at_pointer(GTK_MENU(menu), nullptr);
122 void cache_maintenance(const gchar *path)
124 cache_maintenance_path = g_strdup(path);
126 status_icon = gtk_status_icon_new_from_pixbuf(pixbuf_inline(PIXBUF_INLINE_ICON));
127 gtk_status_icon_set_tooltip_text(status_icon, _("Geeqie: Cleaning thumbs..."));
128 gtk_status_icon_set_visible(status_icon, TRUE);
129 g_signal_connect(G_OBJECT(status_icon), "activate", G_CALLBACK(cache_maintenance_status_icon_activate_cb), NULL);
131 cache_maintain_home_remote(FALSE, FALSE, reinterpret_cast<GDestroyNotify *>(cache_maintenance_clean_stop_cb));
135 *-------------------------------------------------------------------
137 *-------------------------------------------------------------------
140 static gchar *extension_find_dot(gchar *path)
142 gchar *dot = nullptr;
144 if (!path) return nullptr;
146 while (*path != '\0')
148 if (*path == '.') dot = path;
155 static gboolean isempty(const gchar *path)
161 pathl = path_from_utf8(path);
164 if (!dp) return FALSE;
166 while ((dir = readdir(dp)) != nullptr)
168 gchar *name = dir->d_name;
170 if (name[0] != '.' || (name[1] != '\0' && (name[1] != '.' || name[2] != '\0')) )
181 static void cache_maintain_home_close(CMData *cm)
183 if (cm->idle_id) g_source_remove(cm->idle_id);
184 if (cm->gd) generic_dialog_close(cm->gd);
185 filelist_free(cm->list);
186 g_list_free(cm->done_list);
190 static void cache_maintain_home_stop(CMData *cm)
194 g_source_remove(cm->idle_id);
200 gq_gtk_entry_set_text(GTK_ENTRY(cm->entry), _("done"));
201 gtk_spinner_stop(GTK_SPINNER(cm->spinner));
203 gtk_widget_set_sensitive(cm->button_stop, FALSE);
204 gtk_widget_set_sensitive(cm->button_close, TRUE);
208 static gboolean cache_maintain_home_cb(gpointer data)
210 auto cm = static_cast<CMData *>(data);
211 GList *dlist = nullptr;
212 GList *list = nullptr;
214 gboolean just_done = FALSE;
215 gboolean still_have_a_file = TRUE;
217 const gchar *cache_folder;
218 gboolean filter_disable;
222 cache_folder = get_metadata_cache_dir();
226 cache_folder = get_thumbnails_cache_dir();
229 base_length = strlen(cache_folder);
233 DEBUG_1("purge chk done.");
235 cache_maintain_home_stop(cm);
236 return G_SOURCE_REMOVE;
239 fd = static_cast<FileData *>(cm->list->data);
241 DEBUG_1("purge chk (%d) \"%s\"", (cm->clear && !cm->metadata), fd->path);
244 * It is necessary to disable the file filter when clearing the cache,
245 * otherwise the .sim (file similarity) files are not deleted.
247 filter_disable = options->file_filter.disable;
248 options->file_filter.disable = TRUE;
250 if (g_list_find(cm->done_list, fd) == nullptr)
252 cm->done_list = g_list_prepend(cm->done_list, fd);
254 if (filelist_read(fd, &list, &dlist))
259 still_have_a_file = FALSE;
264 auto fd_list = static_cast<FileData *>(work->data);
265 gchar *path_buf = g_strdup(fd_list->path);
268 dot = extension_find_dot(path_buf);
270 if (dot) *dot = '\0';
271 if ((!cm->metadata && cm->clear) ||
272 (strlen(path_buf) > base_length && !isfile(path_buf + base_length)) )
275 if (!unlink_file(path_buf)) log_printf("failed to delete:%s\n", path_buf);
279 still_have_a_file = TRUE;
286 options->file_filter.disable = filter_disable;
290 cm->list = g_list_concat(dlist, cm->list);
292 if (cm->list && g_list_find(cm->done_list, cm->list->data) != nullptr)
294 /* check if the dir is empty */
296 if (cm->list->data == fd && just_done)
298 if (!still_have_a_file && !dlist && cm->list->next && !rmdir_utf8(fd->path))
300 log_printf("Unable to delete dir: %s\n", fd->path);
305 /* must re-check for an empty dir */
306 if (isempty(fd->path) && cm->list->next && !rmdir_utf8(fd->path))
308 log_printf("Unable to delete dir: %s\n", fd->path);
312 fd = static_cast<FileData *>(cm->list->data);
313 cm->done_list = g_list_remove(cm->done_list, fd);
314 cm->list = g_list_remove(cm->list, fd);
318 if (cm->list && !cm->remote)
322 fd = static_cast<FileData *>(cm->list->data);
323 if (strlen(fd->path) > base_length)
325 buf = fd->path + base_length;
331 gq_gtk_entry_set_text(GTK_ENTRY(cm->entry), buf);
334 return G_SOURCE_CONTINUE;
337 static void cache_maintain_home_close_cb(GenericDialog *, gpointer data)
339 auto cm = static_cast<CMData *>(data);
341 if (!gtk_widget_get_sensitive(cm->button_close)) return;
343 cache_maintain_home_close(cm);
346 static void cache_maintain_home_stop_cb(GenericDialog *, gpointer data)
348 auto cm = static_cast<CMData *>(data);
350 cache_maintain_home_stop(cm);
353 /* sorry for complexity (cm->done_list), but need it to remove empty dirs */
354 void cache_maintain_home(gboolean metadata, gboolean clear, GtkWidget *parent)
360 const gchar *cache_folder;
365 cache_folder = get_metadata_cache_dir();
369 cache_folder = get_thumbnails_cache_dir();
372 dir_fd = file_data_new_dir(cache_folder);
373 if (!filelist_read(dir_fd, nullptr, &dlist))
375 file_data_unref(dir_fd);
379 dlist = g_list_append(dlist, dir_fd);
381 cm = g_new0(CMData, 1);
383 cm->done_list = nullptr;
385 cm->metadata = metadata;
390 msg = _("Removing old metadata...");
394 msg = _("Clearing cached thumbnails...");
398 msg = _("Removing old thumbnails...");
401 cm->gd = generic_dialog_new(_("Maintenance"),
405 cm->gd->cancel_cb = cache_maintain_home_close_cb;
406 cm->button_close = generic_dialog_add_button(cm->gd, GQ_ICON_CLOSE, _("Close"),
407 cache_maintain_home_close_cb, FALSE);
408 gtk_widget_set_sensitive(cm->button_close, FALSE);
409 cm->button_stop = generic_dialog_add_button(cm->gd, GQ_ICON_STOP, _("Stop"),
410 cache_maintain_home_stop_cb, FALSE);
412 generic_dialog_add_message(cm->gd, nullptr, msg, nullptr, FALSE);
413 gtk_window_set_default_size(GTK_WINDOW(cm->gd->dialog), PURGE_DIALOG_WIDTH, -1);
415 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
416 gq_gtk_box_pack_start(GTK_BOX(cm->gd->vbox), hbox, FALSE, FALSE, 5);
417 gtk_widget_show(hbox);
419 cm->entry = gtk_entry_new();
420 gtk_widget_set_can_focus(cm->entry, FALSE);
421 gtk_editable_set_editable(GTK_EDITABLE(cm->entry), FALSE);
422 gq_gtk_box_pack_start(GTK_BOX(hbox), cm->entry, TRUE, TRUE, 0);
423 gtk_widget_show(cm->entry);
425 cm->spinner = gtk_spinner_new();
426 gtk_spinner_start(GTK_SPINNER(cm->spinner));
427 gq_gtk_box_pack_start(GTK_BOX(hbox), cm->spinner, FALSE, FALSE, 0);
428 gtk_widget_show(cm->spinner);
430 gtk_widget_show(cm->gd->dialog);
432 cm->idle_id = g_idle_add(cache_maintain_home_cb, cm);
436 * @brief Clears or culls cached data
437 * @param metadata TRUE - work on metadata cache, FALSE - work on thumbnail cache
438 * @param clear TRUE - clear cache, FALSE - delete orphaned cached items
439 * @param func Function called when idle loop function terminates
443 void cache_maintain_home_remote(gboolean metadata, gboolean clear, GDestroyNotify *func)
448 const gchar *cache_folder;
452 cache_folder = get_metadata_cache_dir();
456 cache_folder = get_thumbnails_cache_dir();
459 dir_fd = file_data_new_dir(cache_folder);
460 if (!filelist_read(dir_fd, nullptr, &dlist))
462 file_data_unref(dir_fd);
466 dlist = g_list_append(dlist, dir_fd);
468 cm = g_new0(CMData, 1);
470 cm->done_list = nullptr;
472 cm->metadata = metadata;
475 cm->idle_id = g_idle_add_full(G_PRIORITY_LOW, cache_maintain_home_cb, cm, reinterpret_cast<GDestroyNotify>(func));
478 static void cache_file_move(const gchar *src, const gchar *dest)
480 if (!dest || !src || !isfile(src)) return;
482 if (!move_file(src, dest))
484 DEBUG_1("Failed to move cache file \"%s\" to \"%s\"", src, dest);
485 /* we remove it anyway - it's stale */
490 static void cache_maint_moved(FileData *fd)
494 const gchar *src = fd->change->source;
495 const gchar *dest = fd->change->dest;
497 if (!src || !dest) return;
499 base = cache_get_location(CACHE_TYPE_THUMB, dest, FALSE, &mode);
500 if (recursive_mkdir_if_not_exists(base, mode))
505 buf = cache_find_location(CACHE_TYPE_THUMB, src);
506 d = cache_get_location(CACHE_TYPE_THUMB, dest, TRUE, nullptr);
507 cache_file_move(buf, d);
511 buf = cache_find_location(CACHE_TYPE_SIM, src);
512 d = cache_get_location(CACHE_TYPE_SIM, dest, TRUE, nullptr);
513 cache_file_move(buf, d);
519 log_printf("Failed to create cache dir for move %s\n", base);
523 base = cache_get_location(CACHE_TYPE_METADATA, dest, FALSE, &mode);
524 if (recursive_mkdir_if_not_exists(base, mode))
529 buf = cache_find_location(CACHE_TYPE_METADATA, src);
530 d = cache_get_location(CACHE_TYPE_METADATA, dest, TRUE, nullptr);
531 cache_file_move(buf, d);
537 if (options->thumbnails.enable_caching && options->thumbnails.spec_standard)
538 thumb_std_maint_moved(src, dest);
541 static void cache_file_remove(const gchar *path)
543 if (path && isfile(path) && !unlink_file(path))
545 DEBUG_1("Failed to remove cache file %s", path);
549 static void cache_maint_removed(FileData *fd)
553 buf = cache_find_location(CACHE_TYPE_THUMB, fd->path);
554 cache_file_remove(buf);
557 buf = cache_find_location(CACHE_TYPE_SIM, fd->path);
558 cache_file_remove(buf);
561 buf = cache_find_location(CACHE_TYPE_METADATA, fd->path);
562 cache_file_remove(buf);
565 if (options->thumbnails.enable_caching && options->thumbnails.spec_standard)
566 thumb_std_maint_removed(fd->path);
569 static void cache_maint_copied(FileData *fd)
575 src_cache = cache_find_location(CACHE_TYPE_METADATA, fd->change->source);
576 if (!src_cache) return;
578 dest_base = cache_get_location(CACHE_TYPE_METADATA, fd->change->dest, FALSE, &mode);
579 if (recursive_mkdir_if_not_exists(dest_base, mode))
583 path = cache_get_location(CACHE_TYPE_METADATA, fd->change->dest, TRUE, nullptr);
584 if (!copy_file(src_cache, path))
586 DEBUG_1("failed to copy metadata %s to %s", src_cache, path);
595 void cache_notify_cb(FileData *fd, NotifyType type, gpointer)
597 if (!(type & NOTIFY_CHANGE) || !fd->change) return;
599 DEBUG_1("Notify cache_maint: %s %04x", fd->path, type);
600 switch (fd->change->type)
602 case FILEDATA_CHANGE_MOVE:
603 case FILEDATA_CHANGE_RENAME:
604 cache_maint_moved(fd);
606 case FILEDATA_CHANGE_COPY:
607 cache_maint_copied(fd);
609 case FILEDATA_CHANGE_DELETE:
610 cache_maint_removed(fd);
612 case FILEDATA_CHANGE_UNSPECIFIED:
613 case FILEDATA_CHANGE_WRITE_METADATA:
620 *-------------------------------------------------------------------
621 * new cache maintenance utilities
622 *-------------------------------------------------------------------
627 GenericDialog *dialog;
628 GtkWidget *folder_entry;
642 GDestroyNotify *destroy_func; /* Used by the command line prog. functions */
650 GtkWidget *button_close;
651 GtkWidget *button_stop;
652 GtkWidget *button_start;
654 GtkWidget *progress_bar;
668 guint idle_id; /* event source id */
671 static void cache_manager_render_reset(CacheOpsData *cd)
673 filelist_free(cd->list);
676 filelist_free(cd->list_dir);
677 cd->list_dir = nullptr;
679 thumb_loader_free(reinterpret_cast<ThumbLoader *>(cd->tl));
683 static void cache_manager_render_close_cb(GenericDialog *, gpointer data)
685 auto cd = static_cast<CacheOpsData *>(data);
687 if (!gtk_widget_get_sensitive(cd->button_close)) return;
689 cache_manager_render_reset(cd);
690 generic_dialog_close(cd->gd);
694 static void cache_manager_render_finish(CacheOpsData *cd)
696 cache_manager_render_reset(cd);
699 gq_gtk_entry_set_text(GTK_ENTRY(cd->progress), _("done"));
700 gtk_spinner_stop(GTK_SPINNER(cd->spinner));
702 gtk_widget_set_sensitive(cd->group, TRUE);
703 gtk_widget_set_sensitive(cd->button_start, TRUE);
704 gtk_widget_set_sensitive(cd->button_stop, FALSE);
705 gtk_widget_set_sensitive(cd->button_close, TRUE);
709 static void cache_manager_render_stop_cb(GenericDialog *, gpointer data)
711 auto cd = static_cast<CacheOpsData *>(data);
713 gq_gtk_entry_set_text(GTK_ENTRY(cd->progress), _("stopped"));
714 cache_manager_render_finish(cd);
717 static void cache_manager_render_folder(CacheOpsData *cd, FileData *dir_fd)
719 GList *list_d = nullptr;
720 GList *list_f = nullptr;
724 filelist_read(dir_fd, &list_f, &list_d);
728 filelist_read(dir_fd, &list_f, nullptr);
731 list_f = filelist_filter(list_f, FALSE);
732 list_d = filelist_filter(list_d, TRUE);
734 cd->list = g_list_concat(list_f, cd->list);
735 cd->list_dir = g_list_concat(list_d, cd->list_dir);
738 static gboolean cache_manager_render_file(CacheOpsData *cd);
740 static void cache_manager_render_thumb_done_cb(ThumbLoader *, gpointer data)
742 auto cd = static_cast<CacheOpsData *>(data);
744 thumb_loader_free(reinterpret_cast<ThumbLoader *>(cd->tl));
747 while (cache_manager_render_file(cd));
750 static gboolean cache_manager_render_file(CacheOpsData *cd)
757 fd = static_cast<FileData *>(cd->list->data);
758 cd->list = g_list_remove(cd->list, fd);
760 cd->tl = reinterpret_cast<ThumbLoaderStd *>(thumb_loader_new(options->thumbnails.max_width, options->thumbnails.max_height));
761 thumb_loader_set_callbacks(reinterpret_cast<ThumbLoader *>(cd->tl),
762 cache_manager_render_thumb_done_cb,
763 cache_manager_render_thumb_done_cb,
765 thumb_loader_set_cache(reinterpret_cast<ThumbLoader *>(cd->tl), TRUE, cd->local, TRUE);
766 success = thumb_loader_start(reinterpret_cast<ThumbLoader *>(cd->tl), fd);
771 gq_gtk_entry_set_text(GTK_ENTRY(cd->progress), fd->path);
772 cd->count_done = cd->count_done + 1;
773 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(cd->progress_bar), static_cast<gdouble>(cd->count_done) / cd->count_total);
778 thumb_loader_free(reinterpret_cast<ThumbLoader *>(cd->tl));
790 fd = static_cast<FileData *>(cd->list_dir->data);
791 cd->list_dir = g_list_remove(cd->list_dir, fd);
793 cache_manager_render_folder(cd, fd);
802 gq_gtk_entry_set_text(GTK_ENTRY(cd->progress), _("done"));
804 cache_manager_render_finish(cd);
806 if (cd->destroy_func)
808 g_idle_add(reinterpret_cast<GSourceFunc>(cd->destroy_func), nullptr);
814 static void cache_manager_render_start_cb(GenericDialog *, gpointer data)
816 auto cd = static_cast<CacheOpsData *>(data);
818 GList *list_total = nullptr;
822 if (cd->list || !gtk_widget_get_sensitive(cd->button_start)) return;
825 path = remove_trailing_slash((gq_gtk_entry_get_text(GTK_ENTRY(cd->entry))));
826 parse_out_relatives(path);
832 warning_dialog(_("Invalid folder"),
833 _("The specified folder can not be found."),
834 GQ_ICON_DIALOG_WARNING, cd->gd->dialog);
838 log_printf("The specified folder can not be found: %s\n", path);
846 gtk_widget_set_sensitive(cd->group, FALSE);
847 gtk_widget_set_sensitive(cd->button_start, FALSE);
848 gtk_widget_set_sensitive(cd->button_stop, TRUE);
849 gtk_widget_set_sensitive(cd->button_close, FALSE);
851 gtk_spinner_start(GTK_SPINNER(cd->spinner));
853 dir_fd = file_data_new_dir(path);
854 cache_manager_render_folder(cd, dir_fd);
855 list_total = filelist_recursive(dir_fd);
856 cd->count_total = g_list_length(list_total);
857 file_data_unref(dir_fd);
858 g_list_free(list_total);
861 while (cache_manager_render_file(cd));
867 static void cache_manager_render_start_render_remote(CacheOpsData *cd, const gchar *user_path)
871 path = remove_trailing_slash(user_path);
872 parse_out_relatives(path);
876 log_printf("The specified folder can not be found: %s\n", path);
882 dir_fd = file_data_new_dir(path);
883 cache_manager_render_folder(cd, dir_fd);
884 file_data_unref(dir_fd);
885 while (cache_manager_render_file(cd));
891 static void cache_manager_render_dialog(GtkWidget *widget, const gchar *path)
898 cd = g_new0(CacheOpsData, 1);
901 cd->gd = generic_dialog_new(_("Create thumbnails"),
905 gtk_window_set_default_size(GTK_WINDOW(cd->gd->dialog), PURGE_DIALOG_WIDTH, -1);
906 cd->gd->cancel_cb = cache_manager_render_close_cb;
907 cd->button_close = generic_dialog_add_button(cd->gd, GQ_ICON_CLOSE, _("Close"),
908 cache_manager_render_close_cb, FALSE);
909 cd->button_start = generic_dialog_add_button(cd->gd, GQ_ICON_OK, _("S_tart"),
910 cache_manager_render_start_cb, FALSE);
911 cd->button_stop = generic_dialog_add_button(cd->gd, GQ_ICON_STOP, _("Stop"),
912 cache_manager_render_stop_cb, FALSE);
913 gtk_widget_set_sensitive(cd->button_stop, FALSE);
915 generic_dialog_add_message(cd->gd, nullptr, _("Create thumbnails"), nullptr, FALSE);
917 hbox = pref_box_new(cd->gd->vbox, FALSE, GTK_ORIENTATION_HORIZONTAL, 0);
918 pref_spacer(hbox, PREF_PAD_INDENT);
919 cd->group = pref_box_new(hbox, TRUE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
921 hbox = pref_box_new(cd->group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
922 pref_label_new(hbox, _("Folder:"));
924 label = tab_completion_new(&cd->entry, path, nullptr, nullptr, nullptr, nullptr);
925 tab_completion_add_select_button(cd->entry,_("Select folder") , TRUE);
926 gq_gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0);
927 gtk_widget_show(label);
929 pref_checkbox_new_int(cd->group, _("Include subfolders"), FALSE, &cd->recurse);
930 button = pref_checkbox_new_int(cd->group, _("Store thumbnails local to source images"), FALSE, &cd->local);
931 gtk_widget_set_sensitive(button, options->thumbnails.spec_standard);
933 pref_line(cd->gd->vbox, PREF_PAD_SPACE);
934 hbox = pref_box_new(cd->gd->vbox, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
936 cd->progress = gtk_entry_new();
937 gtk_widget_set_can_focus(cd->progress, FALSE);
938 gtk_editable_set_editable(GTK_EDITABLE(cd->progress), FALSE);
939 gq_gtk_entry_set_text(GTK_ENTRY(cd->progress), _("click start to begin"));
940 gq_gtk_box_pack_start(GTK_BOX(hbox), cd->progress, TRUE, TRUE, 0);
941 gtk_widget_show(cd->progress);
943 cd->progress_bar = gtk_progress_bar_new();
944 gq_gtk_box_pack_start(GTK_BOX(cd->gd->vbox), cd->progress_bar, TRUE, TRUE, 0);
945 gtk_widget_show(cd->progress_bar);
947 cd->spinner = gtk_spinner_new();
948 gq_gtk_box_pack_start(GTK_BOX(hbox), cd->spinner, FALSE, FALSE, 0);
949 gtk_widget_show(cd->spinner);
953 gtk_widget_show(cd->gd->dialog);
957 * @brief Create thumbnails
958 * @param path Path to image folder
960 * @param local Create thumbnails in same folder as images
961 * @param func Function called when idle loop function terminates
965 void cache_manager_render_remote(const gchar *path, gboolean recurse, gboolean local, GDestroyNotify *func)
969 cd = g_new0(CacheOpsData, 1);
970 cd->recurse = recurse;
973 cd->destroy_func = func;
975 cache_manager_render_start_render_remote(cd, path);
978 static void cache_manager_standard_clean_close_cb(GenericDialog *, gpointer data)
980 auto cd = static_cast<CacheOpsData *>(data);
982 if (!gtk_widget_get_sensitive(cd->button_close)) return;
984 generic_dialog_close(cd->gd);
986 thumb_loader_std_thumb_file_validate_cancel(cd->tl);
987 filelist_free(cd->list);
991 static void cache_manager_standard_clean_done(CacheOpsData *cd)
995 gtk_widget_set_sensitive(cd->button_stop, FALSE);
996 gtk_widget_set_sensitive(cd->button_close, TRUE);
998 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(cd->progress), 1.0);
999 gtk_progress_bar_set_text(GTK_PROGRESS_BAR(cd->progress), _("done"));
1003 g_source_remove(cd->idle_id);
1007 thumb_loader_std_thumb_file_validate_cancel(cd->tl);
1010 filelist_free(cd->list);
1014 static void cache_manager_standard_clean_stop_cb(GenericDialog *, gpointer data)
1016 auto cd = static_cast<CacheOpsData *>(data);
1018 cache_manager_standard_clean_done(cd);
1021 static gint cache_manager_standard_clean_clear_cb(gpointer data)
1023 auto cd = static_cast<CacheOpsData *>(data);
1029 next_fd = static_cast<FileData *>(cd->list->data);
1030 cd->list = g_list_remove(cd->list, next_fd);
1032 DEBUG_1("thumb removed: %s", next_fd->path);
1034 unlink_file(next_fd->path);
1035 file_data_unref(next_fd);
1040 if (cd->count_total != 0)
1042 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(cd->progress),
1043 static_cast<gdouble>(cd->count_done) / cd->count_total);
1047 return G_SOURCE_CONTINUE;
1051 cache_manager_standard_clean_done(cd);
1052 return G_SOURCE_REMOVE;
1055 static void cache_manager_standard_clean_valid_cb(const gchar *path, gboolean valid, gpointer data)
1057 auto cd = static_cast<CacheOpsData *>(data);
1063 DEBUG_1("thumb cleaned: %s", path);
1070 if (cd->count_total != 0)
1072 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(cd->progress),
1073 static_cast<gdouble>(cd->count_done) / cd->count_total);
1083 next_fd = static_cast<FileData *>(cd->list->data);
1084 cd->list = g_list_remove(cd->list, next_fd);
1086 cd->tl = thumb_loader_std_thumb_file_validate(next_fd->path, cd->days,
1087 cache_manager_standard_clean_valid_cb, cd);
1088 file_data_unref(next_fd);
1092 cache_manager_standard_clean_done(cd);
1096 static void cache_manager_standard_clean_start(GenericDialog *, gpointer data)
1098 auto cd = static_cast<CacheOpsData *>(data);
1105 if (cd->list || !gtk_widget_get_sensitive(cd->button_start)) return;
1107 gtk_widget_set_sensitive(cd->button_start, FALSE);
1108 gtk_widget_set_sensitive(cd->button_stop, TRUE);
1109 gtk_widget_set_sensitive(cd->button_close, FALSE);
1111 gtk_progress_bar_set_text(GTK_PROGRESS_BAR(cd->progress), _("running..."));
1114 path = g_build_filename(get_thumbnails_standard_cache_dir(), THUMB_FOLDER_NORMAL, NULL);
1115 dir_fd = file_data_new_dir(path);
1116 filelist_read(dir_fd, &list, nullptr);
1118 file_data_unref(dir_fd);
1121 path = g_build_filename(get_thumbnails_standard_cache_dir(), THUMB_FOLDER_LARGE, NULL);
1122 dir_fd = file_data_new_dir(path);
1123 filelist_read(dir_fd, &list, nullptr);
1124 cd->list = g_list_concat(cd->list, list);
1125 file_data_unref(dir_fd);
1128 path = g_build_filename(get_thumbnails_standard_cache_dir(), THUMB_FOLDER_FAIL, NULL);
1129 dir_fd = file_data_new_dir(path);
1130 filelist_read(dir_fd, &list, nullptr);
1131 cd->list = g_list_concat(cd->list, list);
1132 file_data_unref(dir_fd);
1135 cd->count_total = g_list_length(cd->list);
1138 /* start iterating */
1141 cd->idle_id = g_idle_add(cache_manager_standard_clean_clear_cb, cd);
1145 cache_manager_standard_clean_valid_cb(nullptr, TRUE, cd);
1149 static void cache_manager_standard_clean_start_cb(GenericDialog *gd, gpointer data)
1151 cache_manager_standard_clean_start(gd, data);
1154 static void cache_manager_standard_process(GtkWidget *widget, gboolean clear)
1157 const gchar *icon_name;
1160 cd = g_new0(CacheOpsData, 1);
1166 icon_name = GQ_ICON_DELETE;
1167 msg = _("Clearing thumbnails...");
1171 icon_name = GQ_ICON_CLEAR;
1172 msg = _("Removing old thumbnails...");
1175 cd->gd = generic_dialog_new(_("Maintenance"),
1176 "standard_maintenance",
1179 cd->gd->cancel_cb = cache_manager_standard_clean_close_cb;
1180 cd->button_close = generic_dialog_add_button(cd->gd, GQ_ICON_CLOSE, _("Close"),
1181 cache_manager_standard_clean_close_cb, FALSE);
1182 cd->button_start = generic_dialog_add_button(cd->gd, GQ_ICON_OK, _("S_tart"),
1183 cache_manager_standard_clean_start_cb, FALSE);
1184 cd->button_stop = generic_dialog_add_button(cd->gd, GQ_ICON_STOP, _("Stop"),
1185 cache_manager_standard_clean_stop_cb, FALSE);
1186 gtk_widget_set_sensitive(cd->button_stop, FALSE);
1188 generic_dialog_add_message(cd->gd, icon_name, msg, nullptr, FALSE);
1190 cd->progress = gtk_progress_bar_new();
1191 gtk_progress_bar_set_text(GTK_PROGRESS_BAR(cd->progress), _("click start to begin"));
1192 gtk_progress_bar_set_show_text(GTK_PROGRESS_BAR(cd->progress), TRUE);
1193 gq_gtk_box_pack_start(GTK_BOX(cd->gd->vbox), cd->progress, FALSE, FALSE, 0);
1194 gtk_widget_show(cd->progress);
1200 gtk_widget_show(cd->gd->dialog);
1203 void cache_manager_standard_process_remote(gboolean clear)
1207 cd = g_new0(CacheOpsData, 1);
1214 cache_manager_standard_clean_start(nullptr, cd);
1217 static void cache_manager_standard_clean_cb(GtkWidget *widget, gpointer)
1219 cache_manager_standard_process(widget, FALSE);
1222 static void cache_manager_standard_clear_cb(GtkWidget *widget, gpointer)
1224 cache_manager_standard_process(widget, TRUE);
1228 static void cache_manager_main_clean_cb(GtkWidget *widget, gpointer)
1230 cache_maintain_home(FALSE, FALSE, widget);
1234 static void dummy_cancel_cb(GenericDialog *, gpointer)
1236 /* no op, only so cancel button appears */
1239 static void cache_manager_main_clear_ok_cb(GenericDialog *, gpointer)
1241 cache_maintain_home(FALSE, TRUE, nullptr);
1244 void cache_manager_main_clear_confirm(GtkWidget *parent)
1248 gd = generic_dialog_new(_("Clear cache"),
1249 "clear_cache", parent, TRUE,
1250 dummy_cancel_cb, nullptr);
1251 generic_dialog_add_message(gd, GQ_ICON_DIALOG_QUESTION, _("Clear cache"),
1252 _("This will remove all thumbnails and sim. files\nthat have been saved to disk, continue?"), TRUE);
1253 generic_dialog_add_button(gd, GQ_ICON_OK, "OK", cache_manager_main_clear_ok_cb, TRUE);
1255 gtk_widget_show(gd->dialog);
1258 static void cache_manager_main_clear_cb(GtkWidget *widget, gpointer)
1260 cache_manager_main_clear_confirm(widget);
1263 static void cache_manager_render_cb(GtkWidget *widget, gpointer)
1265 const gchar *path = layout_get_path(nullptr);
1267 if (!path || !*path) path = homedir();
1268 cache_manager_render_dialog(widget, path);
1271 static void cache_manager_metadata_clean_cb(GtkWidget *widget, gpointer)
1273 cache_maintain_home(TRUE, FALSE, widget);
1277 static CacheManager *cache_manager = nullptr;
1279 static void cache_manager_close_cb(GenericDialog *gd, gpointer)
1281 generic_dialog_close(gd);
1283 g_free(cache_manager);
1284 cache_manager = nullptr;
1287 static void cache_manager_help_cb(GenericDialog *, gpointer)
1289 help_window_show("GuideReferenceManagement.html");
1292 static GtkWidget *cache_manager_location_label(GtkWidget *group, const gchar *subdir)
1297 buf = g_strdup_printf(_("Location: %s"), subdir);
1298 label = pref_label_new(group, buf);
1300 gtk_label_set_xalign(GTK_LABEL(label), 0.0);
1301 gtk_label_set_yalign(GTK_LABEL(label), 0.5);
1306 static gboolean cache_manager_sim_file(CacheOpsData *cd);
1308 static void cache_manager_sim_reset(CacheOpsData *cd)
1310 filelist_free(cd->list);
1313 filelist_free(cd->list_dir);
1314 cd->list_dir = nullptr;
1316 cache_loader_free(cd->cl);
1320 static void cache_manager_sim_close_cb(GenericDialog *, gpointer data)
1322 auto cd = static_cast<CacheOpsData *>(data);
1324 if (!gtk_widget_get_sensitive(cd->button_close)) return;
1326 cache_manager_sim_reset(cd);
1327 generic_dialog_close(cd->gd);
1331 static void cache_manager_sim_finish(CacheOpsData *cd)
1333 cache_manager_sim_reset(cd);
1336 gtk_spinner_stop(GTK_SPINNER(cd->spinner));
1338 gtk_widget_set_sensitive(cd->group, TRUE);
1339 gtk_widget_set_sensitive(cd->button_start, TRUE);
1340 gtk_widget_set_sensitive(cd->button_stop, FALSE);
1341 gtk_widget_set_sensitive(cd->button_close, TRUE);
1345 static void cache_manager_sim_stop_cb(GenericDialog *, gpointer data)
1347 auto cd = static_cast<CacheOpsData *>(data);
1349 gq_gtk_entry_set_text(GTK_ENTRY(cd->progress), _("stopped"));
1350 cache_manager_sim_finish(cd);
1353 static void cache_manager_sim_folder(CacheOpsData *cd, FileData *dir_fd)
1355 GList *list_d = nullptr;
1356 GList *list_f = nullptr;
1360 filelist_read(dir_fd, &list_f, &list_d);
1364 filelist_read(dir_fd, &list_f, nullptr);
1367 list_f = filelist_filter(list_f, FALSE);
1368 list_d = filelist_filter(list_d, TRUE);
1370 cd->list = g_list_concat(list_f, cd->list);
1371 cd->list_dir = g_list_concat(list_d, cd->list_dir);
1374 static void cache_manager_sim_file_done_cb(CacheLoader *, gint, gpointer data)
1376 auto cd = static_cast<CacheOpsData *>(data);
1378 cache_loader_free(cd->cl);
1381 while (cache_manager_sim_file(cd));
1384 static void cache_manager_sim_start_sim_remote(CacheOpsData *cd, const gchar *user_path)
1388 path = remove_trailing_slash(user_path);
1389 parse_out_relatives(path);
1393 log_printf("The specified folder can not be found: %s\n", path);
1399 dir_fd = file_data_new_dir(path);
1400 cache_manager_sim_folder(cd, dir_fd);
1401 file_data_unref(dir_fd);
1402 while (cache_manager_sim_file(cd));
1409 * @brief Generate .sim files
1410 * @param path Path to image folder
1412 * @param func Function called when idle loop function terminates
1416 void cache_manager_sim_remote(const gchar *path, gboolean recurse, GDestroyNotify *func)
1420 cd = g_new0(CacheOpsData, 1);
1421 cd->recurse = recurse;
1423 cd->destroy_func = func;
1425 cache_manager_sim_start_sim_remote(cd, path);
1428 static gboolean cache_manager_sim_file(CacheOpsData *cd)
1430 CacheDataType load_mask;
1435 fd = static_cast<FileData *>(cd->list->data);
1436 cd->list = g_list_remove(cd->list, fd);
1438 load_mask = static_cast<CacheDataType>(CACHE_LOADER_DIMENSIONS | CACHE_LOADER_DATE | CACHE_LOADER_MD5SUM | CACHE_LOADER_SIMILARITY);
1439 cd->cl = cache_loader_new(fd, load_mask, (cache_manager_sim_file_done_cb), cd);
1443 gq_gtk_entry_set_text(GTK_ENTRY(cd->progress), fd->path);
1446 file_data_unref(fd);
1447 cd->count_done = cd->count_done + 1;
1450 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(cd->progress_bar), static_cast<gdouble>(cd->count_done) / cd->count_total);
1459 fd = static_cast<FileData *>(cd->list_dir->data);
1460 cd->list_dir = g_list_remove(cd->list_dir, fd);
1462 cache_manager_sim_folder(cd, fd);
1463 file_data_unref(fd);
1470 gq_gtk_entry_set_text(GTK_ENTRY(cd->progress), _("done"));
1473 cache_manager_sim_finish(cd);
1475 if (cd->destroy_func)
1477 g_idle_add(reinterpret_cast<GSourceFunc>(cd->destroy_func), nullptr);
1483 static void cache_manager_sim_start_cb(GenericDialog *, gpointer data)
1485 auto cd = static_cast<CacheOpsData *>(data);
1487 GList *list_total = nullptr;
1491 if (cd->list || !gtk_widget_get_sensitive(cd->button_start)) return;
1494 path = remove_trailing_slash((gq_gtk_entry_get_text(GTK_ENTRY(cd->entry))));
1495 parse_out_relatives(path);
1501 warning_dialog(_("Invalid folder"),
1502 _("The specified folder can not be found."),
1503 GQ_ICON_DIALOG_WARNING, cd->gd->dialog);
1507 log_printf("The specified folder can not be found: %s\n", path);
1515 gtk_widget_set_sensitive(cd->group, FALSE);
1516 gtk_widget_set_sensitive(cd->button_start, FALSE);
1517 gtk_widget_set_sensitive(cd->button_stop, TRUE);
1518 gtk_widget_set_sensitive(cd->button_close, FALSE);
1520 gtk_spinner_start(GTK_SPINNER(cd->spinner));
1522 dir_fd = file_data_new_dir(path);
1523 cache_manager_sim_folder(cd, dir_fd);
1524 list_total = filelist_recursive(dir_fd);
1525 cd->count_total = g_list_length(list_total);
1526 file_data_unref(dir_fd);
1527 g_list_free(list_total);
1530 while (cache_manager_sim_file(static_cast<CacheOpsData *>(cd)));
1536 static void cache_manager_sim_load_dialog(GtkWidget *widget, const gchar *path)
1542 cd = g_new0(CacheOpsData, 1);
1546 cd->gd = generic_dialog_new(_("Create sim. files"), "create_sim_files", widget, FALSE, nullptr, cd);
1547 gtk_window_set_default_size(GTK_WINDOW(cd->gd->dialog), PURGE_DIALOG_WIDTH, -1);
1548 cd->gd->cancel_cb = cache_manager_sim_close_cb;
1549 cd->button_close = generic_dialog_add_button(cd->gd, GQ_ICON_CLOSE, _("Close"),
1550 cache_manager_sim_close_cb, FALSE);
1551 cd->button_start = generic_dialog_add_button(cd->gd, GQ_ICON_OK, _("S_tart"),
1552 cache_manager_sim_start_cb, FALSE);
1553 cd->button_stop = generic_dialog_add_button(cd->gd, GQ_ICON_STOP, _("Stop"),
1554 cache_manager_sim_stop_cb, FALSE);
1555 gtk_widget_set_sensitive(cd->button_stop, FALSE);
1557 generic_dialog_add_message(cd->gd, nullptr, _("Create sim. files recursively"), nullptr, FALSE);
1559 hbox = pref_box_new(cd->gd->vbox, FALSE, GTK_ORIENTATION_HORIZONTAL, 0);
1560 pref_spacer(hbox, PREF_PAD_INDENT);
1561 cd->group = pref_box_new(hbox, TRUE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
1563 hbox = pref_box_new(cd->group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
1564 pref_label_new(hbox, _("Folder:"));
1566 label = tab_completion_new(&cd->entry, path, nullptr, nullptr, nullptr, nullptr);
1567 tab_completion_add_select_button(cd->entry,_("Select folder") , TRUE);
1568 gq_gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0);
1569 gtk_widget_show(label);
1571 pref_line(cd->gd->vbox, PREF_PAD_SPACE);
1572 hbox = pref_box_new(cd->gd->vbox, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
1574 cd->progress = gtk_entry_new();
1575 gtk_widget_set_can_focus(cd->progress, FALSE);
1576 gtk_editable_set_editable(GTK_EDITABLE(cd->progress), FALSE);
1577 gq_gtk_entry_set_text(GTK_ENTRY(cd->progress), _("click start to begin"));
1578 gq_gtk_box_pack_start(GTK_BOX(hbox), cd->progress, TRUE, TRUE, 0);
1579 gtk_widget_show(cd->progress);
1581 cd->progress_bar = gtk_progress_bar_new();
1582 gq_gtk_box_pack_start(GTK_BOX(cd->gd->vbox), cd->progress_bar, TRUE, TRUE, 0);
1583 gtk_widget_show(cd->progress_bar);
1585 cd->spinner = gtk_spinner_new();
1586 gq_gtk_box_pack_start(GTK_BOX(hbox), cd->spinner, FALSE, FALSE, 0);
1587 gtk_widget_show(cd->spinner);
1591 gtk_widget_show(cd->gd->dialog);
1594 static void cache_manager_sim_load_cb(GtkWidget *widget, gpointer)
1596 const gchar *path = layout_get_path(nullptr);
1598 if (!path || !*path) path = homedir();
1599 cache_manager_sim_load_dialog(widget, path);
1602 static void cache_manager_cache_maintenance_close_cb(GenericDialog *, gpointer data)
1604 auto cd = static_cast<CacheOpsData *>(data);
1606 if (!gtk_widget_get_sensitive(cd->button_close)) return;
1608 cache_manager_sim_reset(cd);
1609 generic_dialog_close(cd->gd);
1613 static void cache_manager_cache_maintenance_start_cb(GenericDialog *, gpointer data)
1615 auto cd = static_cast<CacheOpsData *>(data);
1621 if (cd->list || !gtk_widget_get_sensitive(cd->button_start)) return;
1624 path = remove_trailing_slash((gq_gtk_entry_get_text(GTK_ENTRY(cd->entry))));
1625 parse_out_relatives(path);
1631 warning_dialog(_("Invalid folder"),
1632 _("The specified folder can not be found."),
1633 GQ_ICON_DIALOG_WARNING, cd->gd->dialog);
1637 log_printf("The specified folder can not be found: \"%s\"\n", path);
1642 cmd_line = g_strdup_printf("%s --cache-maintenance \"%s\"", gq_executable_path, path);
1644 g_spawn_command_line_async(cmd_line, nullptr);
1647 generic_dialog_close(cd->gd);
1648 cache_manager_sim_reset(cd);
1655 static void cache_manager_cache_maintenance_load_dialog(GtkWidget *widget, const gchar *path)
1661 cd = g_new0(CacheOpsData, 1);
1665 cd->gd = generic_dialog_new(_("Background cache maintenance"), "background_cache_maintenance", widget, FALSE, nullptr, cd);
1666 gtk_window_set_default_size(GTK_WINDOW(cd->gd->dialog), PURGE_DIALOG_WIDTH, -1);
1667 cd->gd->cancel_cb = cache_manager_cache_maintenance_close_cb;
1668 cd->button_close = generic_dialog_add_button(cd->gd, GQ_ICON_CLOSE, _("Close"),
1669 cache_manager_cache_maintenance_close_cb, FALSE);
1670 cd->button_start = generic_dialog_add_button(cd->gd, GQ_ICON_OK, _("S_tart"),
1671 cache_manager_cache_maintenance_start_cb, FALSE);
1673 generic_dialog_add_message(cd->gd, nullptr, _("Recursively delete orphaned thumbnails\nand .sim files, and create new\nthumbnails and .sim files"), nullptr, FALSE);
1675 hbox = pref_box_new(cd->gd->vbox, FALSE, GTK_ORIENTATION_HORIZONTAL, 0);
1676 pref_spacer(hbox, PREF_PAD_INDENT);
1677 cd->group = pref_box_new(hbox, TRUE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
1679 hbox = pref_box_new(cd->group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
1680 pref_label_new(hbox, _("Folder:"));
1682 label = tab_completion_new(&cd->entry, path, nullptr, nullptr, nullptr, nullptr);
1683 tab_completion_add_select_button(cd->entry,_("Select folder") , TRUE);
1684 gq_gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0);
1685 gtk_widget_show(label);
1689 gtk_widget_show(cd->gd->dialog);
1692 static void cache_manager_cache_maintenance_load_cb(GtkWidget *widget, gpointer)
1694 const gchar *path = layout_get_path(nullptr);
1696 if (!path || !*path) path = homedir();
1697 cache_manager_cache_maintenance_load_dialog(widget, path);
1700 void cache_manager_show()
1706 GtkSizeGroup *sizegroup;
1711 gtk_window_present(GTK_WINDOW(cache_manager->dialog->dialog));
1715 cache_manager = g_new0(CacheManager, 1);
1717 cache_manager->dialog = generic_dialog_new(_("Cache Maintenance"),
1720 nullptr, cache_manager);
1721 gd = cache_manager->dialog;
1723 gd->cancel_cb = cache_manager_close_cb;
1724 generic_dialog_add_button(gd, GQ_ICON_CLOSE, _("Close"),
1725 cache_manager_close_cb, FALSE);
1726 generic_dialog_add_button(gd, GQ_ICON_HELP, _("Help"),
1727 cache_manager_help_cb, FALSE);
1729 generic_dialog_add_message(gd, nullptr, _("Cache and Data Maintenance"), nullptr, FALSE);
1731 sizegroup = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
1733 group = pref_group_new(gd->vbox, FALSE, _("Geeqie thumbnail and sim. cache"), GTK_ORIENTATION_VERTICAL);
1735 cache_manager_location_label(group, get_thumbnails_cache_dir());
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_main_clean_cb), cache_manager);
1741 gtk_size_group_add_widget(sizegroup, button);
1742 pref_table_label(table, 1, 0, _("Remove orphaned or outdated thumbnails and sim. files."), GTK_ALIGN_START);
1744 button = pref_table_button(table, 0, 1, GQ_ICON_DELETE, _("Clear cache"),
1745 G_CALLBACK(cache_manager_main_clear_cb), cache_manager);
1746 gtk_size_group_add_widget(sizegroup, button);
1747 pref_table_label(table, 1, 1, _("Delete all cached data."), GTK_ALIGN_START);
1750 group = pref_group_new(gd->vbox, FALSE, _("Shared thumbnail cache"), GTK_ORIENTATION_VERTICAL);
1752 path = g_build_filename(get_thumbnails_standard_cache_dir(), NULL);
1753 cache_manager_location_label(group, path);
1756 table = pref_table_new(group, 2, 2, FALSE, FALSE);
1758 button = pref_table_button(table, 0, 0, GQ_ICON_CLEAR, _("Clean up"),
1759 G_CALLBACK(cache_manager_standard_clean_cb), cache_manager);
1760 gtk_size_group_add_widget(sizegroup, button);
1761 pref_table_label(table, 1, 0, _("Remove orphaned or outdated thumbnails."), GTK_ALIGN_START);
1763 button = pref_table_button(table, 0, 1, GQ_ICON_DELETE, _("Clear cache"),
1764 G_CALLBACK(cache_manager_standard_clear_cb), cache_manager);
1765 gtk_size_group_add_widget(sizegroup, button);
1766 pref_table_label(table, 1, 1, _("Delete all cached thumbnails."), GTK_ALIGN_START);
1768 group = pref_group_new(gd->vbox, FALSE, _("Create thumbnails"), GTK_ORIENTATION_VERTICAL);
1770 table = pref_table_new(group, 2, 1, FALSE, FALSE);
1772 button = pref_table_button(table, 0, 1, GQ_ICON_RUN, _("Render"),
1773 G_CALLBACK(cache_manager_render_cb), cache_manager);
1774 gtk_size_group_add_widget(sizegroup, button);
1775 pref_table_label(table, 1, 1, _("Render thumbnails for a specific folder."), GTK_ALIGN_START);
1776 gtk_widget_set_sensitive(group, options->thumbnails.enable_caching);
1778 group = pref_group_new(gd->vbox, FALSE, _("File similarity cache"), GTK_ORIENTATION_VERTICAL);
1780 table = pref_table_new(group, 3, 2, FALSE, FALSE);
1782 button = pref_table_button(table, 0, 0, GQ_ICON_RUN, _("Create"),
1783 G_CALLBACK(cache_manager_sim_load_cb), cache_manager);
1784 gtk_size_group_add_widget(sizegroup, button);
1785 pref_table_label(table, 1, 0, _("Create sim. files recursively."), GTK_ALIGN_START);
1786 gtk_widget_set_sensitive(group, options->thumbnails.enable_caching);
1788 group = pref_group_new(gd->vbox, FALSE, _("Metadata"), GTK_ORIENTATION_VERTICAL);
1790 cache_manager_location_label(group, get_metadata_cache_dir());
1792 table = pref_table_new(group, 2, 1, FALSE, FALSE);
1794 button = pref_table_button(table, 0, 0, GQ_ICON_CLEAR, _("Clean up"),
1795 G_CALLBACK(cache_manager_metadata_clean_cb), cache_manager);
1796 gtk_size_group_add_widget(sizegroup, button);
1797 pref_table_label(table, 1, 0, _("Remove orphaned keywords and comments."), GTK_ALIGN_START);
1799 group = pref_group_new(gd->vbox, FALSE, _("Background cache maintenance"), GTK_ORIENTATION_VERTICAL);
1801 table = pref_table_new(group, 3, 2, FALSE, FALSE);
1803 button = pref_table_button(table, 0, 0, GQ_ICON_RUN, _("Select"),
1804 G_CALLBACK(cache_manager_cache_maintenance_load_cb), cache_manager);
1805 gtk_size_group_add_widget(sizegroup, button);
1806 pref_table_label(table, 1, 0, _("Run cache maintenance as a background job."), GTK_ALIGN_START);
1807 gtk_widget_set_sensitive(group, options->thumbnails.enable_caching);
1809 gtk_widget_show(cache_manager->dialog->dialog);
1811 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */