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"
26 #include "cache-loader.h"
33 #include "main-defines.h"
35 #include "pixbuf-util.h"
37 #include "thumb-standard.h"
38 #include "ui-fileops.h"
40 #include "ui-tabcomp.h"
41 #include "ui-utildlg.h"
49 guint idle_id; /* event source id */
53 GtkWidget *button_stop;
54 GtkWidget *button_close;
61 PURGE_DIALOG_WIDTH = 400
65 *-----------------------------------------------------------------------------
66 * Command line cache maintenance program functions *-----------------------------------------------------------------------------
68 static gchar *cache_maintenance_path = nullptr;
69 static GtkStatusIcon *status_icon;
71 static void cache_maintenance_sim_stop_cb(gpointer)
76 static void cache_maintenance_render_stop_cb(gpointer)
78 gtk_status_icon_set_tooltip_text(status_icon, _("Geeqie: Creating sim data..."));
79 cache_manager_sim_remote(cache_maintenance_path, TRUE, reinterpret_cast<GDestroyNotify *>(cache_maintenance_sim_stop_cb));
82 static void cache_maintenance_clean_stop_cb(gpointer)
84 gtk_status_icon_set_tooltip_text(status_icon, _("Geeqie: Creating thumbs..."));
85 cache_manager_render_remote(cache_maintenance_path, TRUE, options->thumbnails.cache_into_dirs, reinterpret_cast<GDestroyNotify *>(cache_maintenance_render_stop_cb));
88 static void cache_maintenance_user_cancel_cb()
93 static void cache_maintenance_status_icon_activate_cb(GtkStatusIcon *, gpointer)
98 menu = gtk_menu_new();
100 item = gtk_menu_item_new_with_label(_("Exit Geeqie Cache Maintenance"));
102 g_signal_connect(G_OBJECT(item), "activate", cache_maintenance_user_cancel_cb, item);
103 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
104 gtk_widget_show(item);
106 /* take ownership of menu */
107 g_object_ref_sink(G_OBJECT(menu));
109 gtk_menu_popup_at_pointer(GTK_MENU(menu), nullptr);
112 void cache_maintenance(const gchar *path)
114 cache_maintenance_path = g_strdup(path);
116 status_icon = gtk_status_icon_new_from_pixbuf(pixbuf_inline(PIXBUF_INLINE_ICON));
117 gtk_status_icon_set_tooltip_text(status_icon, _("Geeqie: Cleaning thumbs..."));
118 gtk_status_icon_set_visible(status_icon, TRUE);
119 g_signal_connect(G_OBJECT(status_icon), "activate", G_CALLBACK(cache_maintenance_status_icon_activate_cb), NULL);
121 cache_maintain_home_remote(FALSE, FALSE, reinterpret_cast<GDestroyNotify *>(cache_maintenance_clean_stop_cb));
125 *-------------------------------------------------------------------
127 *-------------------------------------------------------------------
130 static gchar *extension_find_dot(gchar *path)
132 gchar *dot = nullptr;
134 if (!path) return nullptr;
136 while (*path != '\0')
138 if (*path == '.') dot = path;
145 static gboolean isempty(const gchar *path)
151 pathl = path_from_utf8(path);
154 if (!dp) return FALSE;
156 while ((dir = readdir(dp)) != nullptr)
158 gchar *name = dir->d_name;
160 if (name[0] != '.' || (name[1] != '\0' && (name[1] != '.' || name[2] != '\0')) )
171 static void cache_maintain_home_close(CMData *cm)
173 if (cm->idle_id) g_source_remove(cm->idle_id);
174 if (cm->gd) generic_dialog_close(cm->gd);
175 filelist_free(cm->list);
176 g_list_free(cm->done_list);
180 static void cache_maintain_home_stop(CMData *cm)
184 g_source_remove(cm->idle_id);
190 gq_gtk_entry_set_text(GTK_ENTRY(cm->entry), _("done"));
191 gtk_spinner_stop(GTK_SPINNER(cm->spinner));
193 gtk_widget_set_sensitive(cm->button_stop, FALSE);
194 gtk_widget_set_sensitive(cm->button_close, TRUE);
198 static gboolean cache_maintain_home_cb(gpointer data)
200 auto cm = static_cast<CMData *>(data);
201 GList *dlist = nullptr;
202 GList *list = nullptr;
204 gboolean just_done = FALSE;
205 gboolean still_have_a_file = TRUE;
207 const gchar *cache_folder;
208 gboolean filter_disable;
212 cache_folder = get_metadata_cache_dir();
216 cache_folder = get_thumbnails_cache_dir();
219 base_length = strlen(cache_folder);
223 DEBUG_1("purge chk done.");
225 cache_maintain_home_stop(cm);
226 return G_SOURCE_REMOVE;
229 fd = static_cast<FileData *>(cm->list->data);
231 DEBUG_1("purge chk (%d) \"%s\"", (cm->clear && !cm->metadata), fd->path);
234 * It is necessary to disable the file filter when clearing the cache,
235 * otherwise the .sim (file similarity) files are not deleted.
237 filter_disable = options->file_filter.disable;
238 options->file_filter.disable = TRUE;
240 if (g_list_find(cm->done_list, fd) == nullptr)
242 cm->done_list = g_list_prepend(cm->done_list, fd);
244 if (filelist_read(fd, &list, &dlist))
249 still_have_a_file = FALSE;
254 auto fd_list = static_cast<FileData *>(work->data);
255 gchar *path_buf = g_strdup(fd_list->path);
258 dot = extension_find_dot(path_buf);
260 if (dot) *dot = '\0';
261 if ((!cm->metadata && cm->clear) ||
262 (strlen(path_buf) > base_length && !isfile(path_buf + base_length)) )
265 if (!unlink_file(path_buf)) log_printf("failed to delete:%s\n", path_buf);
269 still_have_a_file = TRUE;
276 options->file_filter.disable = filter_disable;
280 cm->list = g_list_concat(dlist, cm->list);
282 if (cm->list && g_list_find(cm->done_list, cm->list->data) != nullptr)
284 /* check if the dir is empty */
286 if (cm->list->data == fd && just_done)
288 if (!still_have_a_file && !dlist && cm->list->next && !rmdir_utf8(fd->path))
290 log_printf("Unable to delete dir: %s\n", fd->path);
295 /* must re-check for an empty dir */
296 if (isempty(fd->path) && cm->list->next && !rmdir_utf8(fd->path))
298 log_printf("Unable to delete dir: %s\n", fd->path);
302 fd = static_cast<FileData *>(cm->list->data);
303 cm->done_list = g_list_remove(cm->done_list, fd);
304 cm->list = g_list_remove(cm->list, fd);
308 if (cm->list && !cm->remote)
312 fd = static_cast<FileData *>(cm->list->data);
313 if (strlen(fd->path) > base_length)
315 buf = fd->path + base_length;
321 gq_gtk_entry_set_text(GTK_ENTRY(cm->entry), buf);
324 return G_SOURCE_CONTINUE;
327 static void cache_maintain_home_close_cb(GenericDialog *, gpointer data)
329 auto cm = static_cast<CMData *>(data);
331 if (!gtk_widget_get_sensitive(cm->button_close)) return;
333 cache_maintain_home_close(cm);
336 static void cache_maintain_home_stop_cb(GenericDialog *, gpointer data)
338 auto cm = static_cast<CMData *>(data);
340 cache_maintain_home_stop(cm);
343 /* sorry for complexity (cm->done_list), but need it to remove empty dirs */
344 void cache_maintain_home(gboolean metadata, gboolean clear, GtkWidget *parent)
350 const gchar *cache_folder;
355 cache_folder = get_metadata_cache_dir();
359 cache_folder = get_thumbnails_cache_dir();
362 dir_fd = file_data_new_dir(cache_folder);
363 if (!filelist_read(dir_fd, nullptr, &dlist))
365 file_data_unref(dir_fd);
369 dlist = g_list_append(dlist, dir_fd);
371 cm = g_new0(CMData, 1);
373 cm->done_list = nullptr;
375 cm->metadata = metadata;
380 msg = _("Removing old metadata...");
384 msg = _("Clearing cached thumbnails...");
388 msg = _("Removing old thumbnails...");
391 cm->gd = generic_dialog_new(_("Maintenance"),
395 cm->gd->cancel_cb = cache_maintain_home_close_cb;
396 cm->button_close = generic_dialog_add_button(cm->gd, GQ_ICON_CLOSE, _("Close"),
397 cache_maintain_home_close_cb, FALSE);
398 gtk_widget_set_sensitive(cm->button_close, FALSE);
399 cm->button_stop = generic_dialog_add_button(cm->gd, GQ_ICON_STOP, _("Stop"),
400 cache_maintain_home_stop_cb, FALSE);
402 generic_dialog_add_message(cm->gd, nullptr, msg, nullptr, FALSE);
403 gtk_window_set_default_size(GTK_WINDOW(cm->gd->dialog), PURGE_DIALOG_WIDTH, -1);
405 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
406 gq_gtk_box_pack_start(GTK_BOX(cm->gd->vbox), hbox, FALSE, FALSE, 5);
407 gtk_widget_show(hbox);
409 cm->entry = gtk_entry_new();
410 gtk_widget_set_can_focus(cm->entry, FALSE);
411 gtk_editable_set_editable(GTK_EDITABLE(cm->entry), FALSE);
412 gq_gtk_box_pack_start(GTK_BOX(hbox), cm->entry, TRUE, TRUE, 0);
413 gtk_widget_show(cm->entry);
415 cm->spinner = gtk_spinner_new();
416 gtk_spinner_start(GTK_SPINNER(cm->spinner));
417 gq_gtk_box_pack_start(GTK_BOX(hbox), cm->spinner, FALSE, FALSE, 0);
418 gtk_widget_show(cm->spinner);
420 gtk_widget_show(cm->gd->dialog);
422 cm->idle_id = g_idle_add(cache_maintain_home_cb, cm);
426 * @brief Clears or culls cached data
427 * @param metadata TRUE - work on metadata cache, FALSE - work on thumbnail cache
428 * @param clear TRUE - clear cache, FALSE - delete orphaned cached items
429 * @param func Function called when idle loop function terminates
433 void cache_maintain_home_remote(gboolean metadata, gboolean clear, GDestroyNotify *func)
438 const gchar *cache_folder;
442 cache_folder = get_metadata_cache_dir();
446 cache_folder = get_thumbnails_cache_dir();
449 dir_fd = file_data_new_dir(cache_folder);
450 if (!filelist_read(dir_fd, nullptr, &dlist))
452 file_data_unref(dir_fd);
456 dlist = g_list_append(dlist, dir_fd);
458 cm = g_new0(CMData, 1);
460 cm->done_list = nullptr;
462 cm->metadata = metadata;
465 cm->idle_id = g_idle_add_full(G_PRIORITY_LOW, cache_maintain_home_cb, cm, reinterpret_cast<GDestroyNotify>(func));
468 static void cache_file_move(const gchar *src, const gchar *dest)
470 if (!dest || !src || !isfile(src)) return;
472 if (!move_file(src, dest))
474 DEBUG_1("Failed to move cache file \"%s\" to \"%s\"", src, dest);
475 /* we remove it anyway - it's stale */
480 static void cache_maint_moved(FileData *fd)
484 const gchar *src = fd->change->source;
485 const gchar *dest = fd->change->dest;
487 if (!src || !dest) return;
489 base = cache_get_location(CACHE_TYPE_THUMB, dest, FALSE, &mode);
490 if (recursive_mkdir_if_not_exists(base, mode))
495 buf = cache_find_location(CACHE_TYPE_THUMB, src);
496 d = cache_get_location(CACHE_TYPE_THUMB, dest, TRUE, nullptr);
497 cache_file_move(buf, d);
501 buf = cache_find_location(CACHE_TYPE_SIM, src);
502 d = cache_get_location(CACHE_TYPE_SIM, dest, TRUE, nullptr);
503 cache_file_move(buf, d);
509 log_printf("Failed to create cache dir for move %s\n", base);
513 base = cache_get_location(CACHE_TYPE_METADATA, dest, FALSE, &mode);
514 if (recursive_mkdir_if_not_exists(base, mode))
519 buf = cache_find_location(CACHE_TYPE_METADATA, src);
520 d = cache_get_location(CACHE_TYPE_METADATA, dest, TRUE, nullptr);
521 cache_file_move(buf, d);
527 if (options->thumbnails.enable_caching && options->thumbnails.spec_standard)
528 thumb_std_maint_moved(src, dest);
531 static void cache_file_remove(const gchar *path)
533 if (path && isfile(path) && !unlink_file(path))
535 DEBUG_1("Failed to remove cache file %s", path);
539 static void cache_maint_removed(FileData *fd)
543 buf = cache_find_location(CACHE_TYPE_THUMB, fd->path);
544 cache_file_remove(buf);
547 buf = cache_find_location(CACHE_TYPE_SIM, fd->path);
548 cache_file_remove(buf);
551 buf = cache_find_location(CACHE_TYPE_METADATA, fd->path);
552 cache_file_remove(buf);
555 if (options->thumbnails.enable_caching && options->thumbnails.spec_standard)
556 thumb_std_maint_removed(fd->path);
559 static void cache_maint_copied(FileData *fd)
565 src_cache = cache_find_location(CACHE_TYPE_METADATA, fd->change->source);
566 if (!src_cache) return;
568 dest_base = cache_get_location(CACHE_TYPE_METADATA, fd->change->dest, FALSE, &mode);
569 if (recursive_mkdir_if_not_exists(dest_base, mode))
573 path = cache_get_location(CACHE_TYPE_METADATA, fd->change->dest, TRUE, nullptr);
574 if (!copy_file(src_cache, path))
576 DEBUG_1("failed to copy metadata %s to %s", src_cache, path);
585 void cache_notify_cb(FileData *fd, NotifyType type, gpointer)
587 if (!(type & NOTIFY_CHANGE) || !fd->change) return;
589 DEBUG_1("Notify cache_maint: %s %04x", fd->path, type);
590 switch (fd->change->type)
592 case FILEDATA_CHANGE_MOVE:
593 case FILEDATA_CHANGE_RENAME:
594 cache_maint_moved(fd);
596 case FILEDATA_CHANGE_COPY:
597 cache_maint_copied(fd);
599 case FILEDATA_CHANGE_DELETE:
600 cache_maint_removed(fd);
602 case FILEDATA_CHANGE_UNSPECIFIED:
603 case FILEDATA_CHANGE_WRITE_METADATA:
610 *-------------------------------------------------------------------
611 * new cache maintenance utilities
612 *-------------------------------------------------------------------
617 GenericDialog *dialog;
618 GtkWidget *folder_entry;
632 GDestroyNotify *destroy_func; /* Used by the command line prog. functions */
640 GtkWidget *button_close;
641 GtkWidget *button_stop;
642 GtkWidget *button_start;
644 GtkWidget *progress_bar;
658 guint idle_id; /* event source id */
661 static void cache_manager_render_reset(CacheOpsData *cd)
663 filelist_free(cd->list);
666 filelist_free(cd->list_dir);
667 cd->list_dir = nullptr;
669 thumb_loader_free(reinterpret_cast<ThumbLoader *>(cd->tl));
673 static void cache_manager_render_close_cb(GenericDialog *, gpointer data)
675 auto cd = static_cast<CacheOpsData *>(data);
677 if (!gtk_widget_get_sensitive(cd->button_close)) return;
679 cache_manager_render_reset(cd);
680 generic_dialog_close(cd->gd);
684 static void cache_manager_render_finish(CacheOpsData *cd)
686 cache_manager_render_reset(cd);
689 gq_gtk_entry_set_text(GTK_ENTRY(cd->progress), _("done"));
690 gtk_spinner_stop(GTK_SPINNER(cd->spinner));
692 gtk_widget_set_sensitive(cd->group, TRUE);
693 gtk_widget_set_sensitive(cd->button_start, TRUE);
694 gtk_widget_set_sensitive(cd->button_stop, FALSE);
695 gtk_widget_set_sensitive(cd->button_close, TRUE);
699 static void cache_manager_render_stop_cb(GenericDialog *, gpointer data)
701 auto cd = static_cast<CacheOpsData *>(data);
703 gq_gtk_entry_set_text(GTK_ENTRY(cd->progress), _("stopped"));
704 cache_manager_render_finish(cd);
707 static void cache_manager_render_folder(CacheOpsData *cd, FileData *dir_fd)
709 GList *list_d = nullptr;
710 GList *list_f = nullptr;
714 filelist_read(dir_fd, &list_f, &list_d);
718 filelist_read(dir_fd, &list_f, nullptr);
721 list_f = filelist_filter(list_f, FALSE);
722 list_d = filelist_filter(list_d, TRUE);
724 cd->list = g_list_concat(list_f, cd->list);
725 cd->list_dir = g_list_concat(list_d, cd->list_dir);
728 static gboolean cache_manager_render_file(CacheOpsData *cd);
730 static void cache_manager_render_thumb_done_cb(ThumbLoader *, gpointer data)
732 auto cd = static_cast<CacheOpsData *>(data);
734 thumb_loader_free(reinterpret_cast<ThumbLoader *>(cd->tl));
737 while (cache_manager_render_file(cd));
740 static gboolean cache_manager_render_file(CacheOpsData *cd)
747 fd = static_cast<FileData *>(cd->list->data);
748 cd->list = g_list_remove(cd->list, fd);
750 cd->tl = reinterpret_cast<ThumbLoaderStd *>(thumb_loader_new(options->thumbnails.max_width, options->thumbnails.max_height));
751 thumb_loader_set_callbacks(reinterpret_cast<ThumbLoader *>(cd->tl),
752 cache_manager_render_thumb_done_cb,
753 cache_manager_render_thumb_done_cb,
755 thumb_loader_set_cache(reinterpret_cast<ThumbLoader *>(cd->tl), TRUE, cd->local, TRUE);
756 success = thumb_loader_start(reinterpret_cast<ThumbLoader *>(cd->tl), fd);
761 gq_gtk_entry_set_text(GTK_ENTRY(cd->progress), fd->path);
762 cd->count_done = cd->count_done + 1;
763 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(cd->progress_bar), static_cast<gdouble>(cd->count_done) / cd->count_total);
768 thumb_loader_free(reinterpret_cast<ThumbLoader *>(cd->tl));
780 fd = static_cast<FileData *>(cd->list_dir->data);
781 cd->list_dir = g_list_remove(cd->list_dir, fd);
783 cache_manager_render_folder(cd, fd);
792 gq_gtk_entry_set_text(GTK_ENTRY(cd->progress), _("done"));
794 cache_manager_render_finish(cd);
796 if (cd->destroy_func)
798 g_idle_add(reinterpret_cast<GSourceFunc>(cd->destroy_func), nullptr);
804 static void cache_manager_render_start_cb(GenericDialog *, gpointer data)
806 auto cd = static_cast<CacheOpsData *>(data);
808 GList *list_total = nullptr;
812 if (cd->list || !gtk_widget_get_sensitive(cd->button_start)) return;
815 path = remove_trailing_slash((gq_gtk_entry_get_text(GTK_ENTRY(cd->entry))));
816 parse_out_relatives(path);
822 warning_dialog(_("Invalid folder"),
823 _("The specified folder can not be found."),
824 GQ_ICON_DIALOG_WARNING, cd->gd->dialog);
828 log_printf("The specified folder can not be found: %s\n", path);
836 gtk_widget_set_sensitive(cd->group, FALSE);
837 gtk_widget_set_sensitive(cd->button_start, FALSE);
838 gtk_widget_set_sensitive(cd->button_stop, TRUE);
839 gtk_widget_set_sensitive(cd->button_close, FALSE);
841 gtk_spinner_start(GTK_SPINNER(cd->spinner));
843 dir_fd = file_data_new_dir(path);
844 cache_manager_render_folder(cd, dir_fd);
845 list_total = filelist_recursive(dir_fd);
846 cd->count_total = g_list_length(list_total);
847 file_data_unref(dir_fd);
848 g_list_free(list_total);
851 while (cache_manager_render_file(cd));
857 static void cache_manager_render_start_render_remote(CacheOpsData *cd, const gchar *user_path)
861 path = remove_trailing_slash(user_path);
862 parse_out_relatives(path);
866 log_printf("The specified folder can not be found: %s\n", path);
872 dir_fd = file_data_new_dir(path);
873 cache_manager_render_folder(cd, dir_fd);
874 file_data_unref(dir_fd);
875 while (cache_manager_render_file(cd));
881 static void cache_manager_render_dialog(GtkWidget *widget, const gchar *path)
888 cd = g_new0(CacheOpsData, 1);
891 cd->gd = generic_dialog_new(_("Create thumbnails"),
895 gtk_window_set_default_size(GTK_WINDOW(cd->gd->dialog), PURGE_DIALOG_WIDTH, -1);
896 cd->gd->cancel_cb = cache_manager_render_close_cb;
897 cd->button_close = generic_dialog_add_button(cd->gd, GQ_ICON_CLOSE, _("Close"),
898 cache_manager_render_close_cb, FALSE);
899 cd->button_start = generic_dialog_add_button(cd->gd, GQ_ICON_OK, _("S_tart"),
900 cache_manager_render_start_cb, FALSE);
901 cd->button_stop = generic_dialog_add_button(cd->gd, GQ_ICON_STOP, _("Stop"),
902 cache_manager_render_stop_cb, FALSE);
903 gtk_widget_set_sensitive(cd->button_stop, FALSE);
905 generic_dialog_add_message(cd->gd, nullptr, _("Create thumbnails"), nullptr, FALSE);
907 hbox = pref_box_new(cd->gd->vbox, FALSE, GTK_ORIENTATION_HORIZONTAL, 0);
908 pref_spacer(hbox, PREF_PAD_INDENT);
909 cd->group = pref_box_new(hbox, TRUE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
911 hbox = pref_box_new(cd->group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
912 pref_label_new(hbox, _("Folder:"));
914 label = tab_completion_new(&cd->entry, path, nullptr, nullptr, nullptr, nullptr);
915 tab_completion_add_select_button(cd->entry,_("Select folder") , TRUE);
916 gq_gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0);
917 gtk_widget_show(label);
919 pref_checkbox_new_int(cd->group, _("Include subfolders"), FALSE, &cd->recurse);
920 button = pref_checkbox_new_int(cd->group, _("Store thumbnails local to source images"), FALSE, &cd->local);
921 gtk_widget_set_sensitive(button, options->thumbnails.spec_standard);
923 pref_line(cd->gd->vbox, PREF_PAD_SPACE);
924 hbox = pref_box_new(cd->gd->vbox, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
926 cd->progress = gtk_entry_new();
927 gtk_widget_set_can_focus(cd->progress, FALSE);
928 gtk_editable_set_editable(GTK_EDITABLE(cd->progress), FALSE);
929 gq_gtk_entry_set_text(GTK_ENTRY(cd->progress), _("click start to begin"));
930 gq_gtk_box_pack_start(GTK_BOX(hbox), cd->progress, TRUE, TRUE, 0);
931 gtk_widget_show(cd->progress);
933 cd->progress_bar = gtk_progress_bar_new();
934 gq_gtk_box_pack_start(GTK_BOX(cd->gd->vbox), cd->progress_bar, TRUE, TRUE, 0);
935 gtk_widget_show(cd->progress_bar);
937 cd->spinner = gtk_spinner_new();
938 gq_gtk_box_pack_start(GTK_BOX(hbox), cd->spinner, FALSE, FALSE, 0);
939 gtk_widget_show(cd->spinner);
943 gtk_widget_show(cd->gd->dialog);
947 * @brief Create thumbnails
948 * @param path Path to image folder
950 * @param local Create thumbnails in same folder as images
951 * @param func Function called when idle loop function terminates
955 void cache_manager_render_remote(const gchar *path, gboolean recurse, gboolean local, GDestroyNotify *func)
959 cd = g_new0(CacheOpsData, 1);
960 cd->recurse = recurse;
963 cd->destroy_func = func;
965 cache_manager_render_start_render_remote(cd, path);
968 static void cache_manager_standard_clean_close_cb(GenericDialog *, gpointer data)
970 auto cd = static_cast<CacheOpsData *>(data);
972 if (!gtk_widget_get_sensitive(cd->button_close)) return;
974 generic_dialog_close(cd->gd);
976 thumb_loader_std_thumb_file_validate_cancel(cd->tl);
977 filelist_free(cd->list);
981 static void cache_manager_standard_clean_done(CacheOpsData *cd)
985 gtk_widget_set_sensitive(cd->button_stop, FALSE);
986 gtk_widget_set_sensitive(cd->button_close, TRUE);
988 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(cd->progress), 1.0);
989 gtk_progress_bar_set_text(GTK_PROGRESS_BAR(cd->progress), _("done"));
993 g_source_remove(cd->idle_id);
997 thumb_loader_std_thumb_file_validate_cancel(cd->tl);
1000 filelist_free(cd->list);
1004 static void cache_manager_standard_clean_stop_cb(GenericDialog *, gpointer data)
1006 auto cd = static_cast<CacheOpsData *>(data);
1008 cache_manager_standard_clean_done(cd);
1011 static gint cache_manager_standard_clean_clear_cb(gpointer data)
1013 auto cd = static_cast<CacheOpsData *>(data);
1019 next_fd = static_cast<FileData *>(cd->list->data);
1020 cd->list = g_list_remove(cd->list, next_fd);
1022 DEBUG_1("thumb removed: %s", next_fd->path);
1024 unlink_file(next_fd->path);
1025 file_data_unref(next_fd);
1030 if (cd->count_total != 0)
1032 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(cd->progress),
1033 static_cast<gdouble>(cd->count_done) / cd->count_total);
1037 return G_SOURCE_CONTINUE;
1041 cache_manager_standard_clean_done(cd);
1042 return G_SOURCE_REMOVE;
1045 static void cache_manager_standard_clean_valid_cb(const gchar *path, gboolean valid, gpointer data)
1047 auto cd = static_cast<CacheOpsData *>(data);
1053 DEBUG_1("thumb cleaned: %s", path);
1060 if (cd->count_total != 0)
1062 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(cd->progress),
1063 static_cast<gdouble>(cd->count_done) / cd->count_total);
1073 next_fd = static_cast<FileData *>(cd->list->data);
1074 cd->list = g_list_remove(cd->list, next_fd);
1076 cd->tl = thumb_loader_std_thumb_file_validate(next_fd->path, cd->days,
1077 cache_manager_standard_clean_valid_cb, cd);
1078 file_data_unref(next_fd);
1082 cache_manager_standard_clean_done(cd);
1086 static void cache_manager_standard_clean_start(GenericDialog *, gpointer data)
1088 auto cd = static_cast<CacheOpsData *>(data);
1095 if (cd->list || !gtk_widget_get_sensitive(cd->button_start)) return;
1097 gtk_widget_set_sensitive(cd->button_start, FALSE);
1098 gtk_widget_set_sensitive(cd->button_stop, TRUE);
1099 gtk_widget_set_sensitive(cd->button_close, FALSE);
1101 gtk_progress_bar_set_text(GTK_PROGRESS_BAR(cd->progress), _("running..."));
1104 path = g_build_filename(get_thumbnails_standard_cache_dir(), THUMB_FOLDER_NORMAL, NULL);
1105 dir_fd = file_data_new_dir(path);
1106 filelist_read(dir_fd, &list, nullptr);
1108 file_data_unref(dir_fd);
1111 path = g_build_filename(get_thumbnails_standard_cache_dir(), THUMB_FOLDER_LARGE, NULL);
1112 dir_fd = file_data_new_dir(path);
1113 filelist_read(dir_fd, &list, nullptr);
1114 cd->list = g_list_concat(cd->list, list);
1115 file_data_unref(dir_fd);
1118 path = g_build_filename(get_thumbnails_standard_cache_dir(), THUMB_FOLDER_FAIL, NULL);
1119 dir_fd = file_data_new_dir(path);
1120 filelist_read(dir_fd, &list, nullptr);
1121 cd->list = g_list_concat(cd->list, list);
1122 file_data_unref(dir_fd);
1125 cd->count_total = g_list_length(cd->list);
1128 /* start iterating */
1131 cd->idle_id = g_idle_add(cache_manager_standard_clean_clear_cb, cd);
1135 cache_manager_standard_clean_valid_cb(nullptr, TRUE, cd);
1139 static void cache_manager_standard_clean_start_cb(GenericDialog *gd, gpointer data)
1141 cache_manager_standard_clean_start(gd, data);
1144 static void cache_manager_standard_process(GtkWidget *widget, gboolean clear)
1147 const gchar *icon_name;
1150 cd = g_new0(CacheOpsData, 1);
1156 icon_name = GQ_ICON_DELETE;
1157 msg = _("Clearing thumbnails...");
1161 icon_name = GQ_ICON_CLEAR;
1162 msg = _("Removing old thumbnails...");
1165 cd->gd = generic_dialog_new(_("Maintenance"),
1166 "standard_maintenance",
1169 cd->gd->cancel_cb = cache_manager_standard_clean_close_cb;
1170 cd->button_close = generic_dialog_add_button(cd->gd, GQ_ICON_CLOSE, _("Close"),
1171 cache_manager_standard_clean_close_cb, FALSE);
1172 cd->button_start = generic_dialog_add_button(cd->gd, GQ_ICON_OK, _("S_tart"),
1173 cache_manager_standard_clean_start_cb, FALSE);
1174 cd->button_stop = generic_dialog_add_button(cd->gd, GQ_ICON_STOP, _("Stop"),
1175 cache_manager_standard_clean_stop_cb, FALSE);
1176 gtk_widget_set_sensitive(cd->button_stop, FALSE);
1178 generic_dialog_add_message(cd->gd, icon_name, msg, nullptr, FALSE);
1180 cd->progress = gtk_progress_bar_new();
1181 gtk_progress_bar_set_text(GTK_PROGRESS_BAR(cd->progress), _("click start to begin"));
1182 gtk_progress_bar_set_show_text(GTK_PROGRESS_BAR(cd->progress), TRUE);
1183 gq_gtk_box_pack_start(GTK_BOX(cd->gd->vbox), cd->progress, FALSE, FALSE, 0);
1184 gtk_widget_show(cd->progress);
1190 gtk_widget_show(cd->gd->dialog);
1193 void cache_manager_standard_process_remote(gboolean clear)
1197 cd = g_new0(CacheOpsData, 1);
1204 cache_manager_standard_clean_start(nullptr, cd);
1207 static void cache_manager_standard_clean_cb(GtkWidget *widget, gpointer)
1209 cache_manager_standard_process(widget, FALSE);
1212 static void cache_manager_standard_clear_cb(GtkWidget *widget, gpointer)
1214 cache_manager_standard_process(widget, TRUE);
1218 static void cache_manager_main_clean_cb(GtkWidget *widget, gpointer)
1220 cache_maintain_home(FALSE, FALSE, widget);
1224 static void dummy_cancel_cb(GenericDialog *, gpointer)
1226 /* no op, only so cancel button appears */
1229 static void cache_manager_main_clear_ok_cb(GenericDialog *, gpointer)
1231 cache_maintain_home(FALSE, TRUE, nullptr);
1234 void cache_manager_main_clear_confirm(GtkWidget *parent)
1238 gd = generic_dialog_new(_("Clear cache"),
1239 "clear_cache", parent, TRUE,
1240 dummy_cancel_cb, nullptr);
1241 generic_dialog_add_message(gd, GQ_ICON_DIALOG_QUESTION, _("Clear cache"),
1242 _("This will remove all thumbnails and sim. files\nthat have been saved to disk, continue?"), TRUE);
1243 generic_dialog_add_button(gd, GQ_ICON_OK, "OK", cache_manager_main_clear_ok_cb, TRUE);
1245 gtk_widget_show(gd->dialog);
1248 static void cache_manager_main_clear_cb(GtkWidget *widget, gpointer)
1250 cache_manager_main_clear_confirm(widget);
1253 static void cache_manager_render_cb(GtkWidget *widget, gpointer)
1255 const gchar *path = layout_get_path(nullptr);
1257 if (!path || !*path) path = homedir();
1258 cache_manager_render_dialog(widget, path);
1261 static void cache_manager_metadata_clean_cb(GtkWidget *widget, gpointer)
1263 cache_maintain_home(TRUE, FALSE, widget);
1267 static CacheManager *cache_manager = nullptr;
1269 static void cache_manager_close_cb(GenericDialog *gd, gpointer)
1271 generic_dialog_close(gd);
1273 g_free(cache_manager);
1274 cache_manager = nullptr;
1277 static void cache_manager_help_cb(GenericDialog *, gpointer)
1279 help_window_show("GuideReferenceManagement.html");
1282 static GtkWidget *cache_manager_location_label(GtkWidget *group, const gchar *subdir)
1287 buf = g_strdup_printf(_("Location: %s"), subdir);
1288 label = pref_label_new(group, buf);
1290 gtk_label_set_xalign(GTK_LABEL(label), 0.0);
1291 gtk_label_set_yalign(GTK_LABEL(label), 0.5);
1296 static gboolean cache_manager_sim_file(CacheOpsData *cd);
1298 static void cache_manager_sim_reset(CacheOpsData *cd)
1300 filelist_free(cd->list);
1303 filelist_free(cd->list_dir);
1304 cd->list_dir = nullptr;
1306 cache_loader_free(cd->cl);
1310 static void cache_manager_sim_close_cb(GenericDialog *, gpointer data)
1312 auto cd = static_cast<CacheOpsData *>(data);
1314 if (!gtk_widget_get_sensitive(cd->button_close)) return;
1316 cache_manager_sim_reset(cd);
1317 generic_dialog_close(cd->gd);
1321 static void cache_manager_sim_finish(CacheOpsData *cd)
1323 cache_manager_sim_reset(cd);
1326 gtk_spinner_stop(GTK_SPINNER(cd->spinner));
1328 gtk_widget_set_sensitive(cd->group, TRUE);
1329 gtk_widget_set_sensitive(cd->button_start, TRUE);
1330 gtk_widget_set_sensitive(cd->button_stop, FALSE);
1331 gtk_widget_set_sensitive(cd->button_close, TRUE);
1335 static void cache_manager_sim_stop_cb(GenericDialog *, gpointer data)
1337 auto cd = static_cast<CacheOpsData *>(data);
1339 gq_gtk_entry_set_text(GTK_ENTRY(cd->progress), _("stopped"));
1340 cache_manager_sim_finish(cd);
1343 static void cache_manager_sim_folder(CacheOpsData *cd, FileData *dir_fd)
1345 GList *list_d = nullptr;
1346 GList *list_f = nullptr;
1350 filelist_read(dir_fd, &list_f, &list_d);
1354 filelist_read(dir_fd, &list_f, nullptr);
1357 list_f = filelist_filter(list_f, FALSE);
1358 list_d = filelist_filter(list_d, TRUE);
1360 cd->list = g_list_concat(list_f, cd->list);
1361 cd->list_dir = g_list_concat(list_d, cd->list_dir);
1364 static void cache_manager_sim_file_done_cb(CacheLoader *, gint, gpointer data)
1366 auto cd = static_cast<CacheOpsData *>(data);
1368 cache_loader_free(cd->cl);
1371 while (cache_manager_sim_file(cd));
1374 static void cache_manager_sim_start_sim_remote(CacheOpsData *cd, const gchar *user_path)
1378 path = remove_trailing_slash(user_path);
1379 parse_out_relatives(path);
1383 log_printf("The specified folder can not be found: %s\n", path);
1389 dir_fd = file_data_new_dir(path);
1390 cache_manager_sim_folder(cd, dir_fd);
1391 file_data_unref(dir_fd);
1392 while (cache_manager_sim_file(cd));
1399 * @brief Generate .sim files
1400 * @param path Path to image folder
1402 * @param func Function called when idle loop function terminates
1406 void cache_manager_sim_remote(const gchar *path, gboolean recurse, GDestroyNotify *func)
1410 cd = g_new0(CacheOpsData, 1);
1411 cd->recurse = recurse;
1413 cd->destroy_func = func;
1415 cache_manager_sim_start_sim_remote(cd, path);
1418 static gboolean cache_manager_sim_file(CacheOpsData *cd)
1420 CacheDataType load_mask;
1425 fd = static_cast<FileData *>(cd->list->data);
1426 cd->list = g_list_remove(cd->list, fd);
1428 load_mask = static_cast<CacheDataType>(CACHE_LOADER_DIMENSIONS | CACHE_LOADER_DATE | CACHE_LOADER_MD5SUM | CACHE_LOADER_SIMILARITY);
1429 cd->cl = cache_loader_new(fd, load_mask, (cache_manager_sim_file_done_cb), cd);
1433 gq_gtk_entry_set_text(GTK_ENTRY(cd->progress), fd->path);
1436 file_data_unref(fd);
1437 cd->count_done = cd->count_done + 1;
1440 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(cd->progress_bar), static_cast<gdouble>(cd->count_done) / cd->count_total);
1449 fd = static_cast<FileData *>(cd->list_dir->data);
1450 cd->list_dir = g_list_remove(cd->list_dir, fd);
1452 cache_manager_sim_folder(cd, fd);
1453 file_data_unref(fd);
1460 gq_gtk_entry_set_text(GTK_ENTRY(cd->progress), _("done"));
1463 cache_manager_sim_finish(cd);
1465 if (cd->destroy_func)
1467 g_idle_add(reinterpret_cast<GSourceFunc>(cd->destroy_func), nullptr);
1473 static void cache_manager_sim_start_cb(GenericDialog *, gpointer data)
1475 auto cd = static_cast<CacheOpsData *>(data);
1477 GList *list_total = nullptr;
1481 if (cd->list || !gtk_widget_get_sensitive(cd->button_start)) return;
1484 path = remove_trailing_slash((gq_gtk_entry_get_text(GTK_ENTRY(cd->entry))));
1485 parse_out_relatives(path);
1491 warning_dialog(_("Invalid folder"),
1492 _("The specified folder can not be found."),
1493 GQ_ICON_DIALOG_WARNING, cd->gd->dialog);
1497 log_printf("The specified folder can not be found: %s\n", path);
1505 gtk_widget_set_sensitive(cd->group, FALSE);
1506 gtk_widget_set_sensitive(cd->button_start, FALSE);
1507 gtk_widget_set_sensitive(cd->button_stop, TRUE);
1508 gtk_widget_set_sensitive(cd->button_close, FALSE);
1510 gtk_spinner_start(GTK_SPINNER(cd->spinner));
1512 dir_fd = file_data_new_dir(path);
1513 cache_manager_sim_folder(cd, dir_fd);
1514 list_total = filelist_recursive(dir_fd);
1515 cd->count_total = g_list_length(list_total);
1516 file_data_unref(dir_fd);
1517 g_list_free(list_total);
1520 while (cache_manager_sim_file(static_cast<CacheOpsData *>(cd)));
1526 static void cache_manager_sim_load_dialog(GtkWidget *widget, const gchar *path)
1532 cd = g_new0(CacheOpsData, 1);
1536 cd->gd = generic_dialog_new(_("Create sim. files"), "create_sim_files", widget, FALSE, nullptr, cd);
1537 gtk_window_set_default_size(GTK_WINDOW(cd->gd->dialog), PURGE_DIALOG_WIDTH, -1);
1538 cd->gd->cancel_cb = cache_manager_sim_close_cb;
1539 cd->button_close = generic_dialog_add_button(cd->gd, GQ_ICON_CLOSE, _("Close"),
1540 cache_manager_sim_close_cb, FALSE);
1541 cd->button_start = generic_dialog_add_button(cd->gd, GQ_ICON_OK, _("S_tart"),
1542 cache_manager_sim_start_cb, FALSE);
1543 cd->button_stop = generic_dialog_add_button(cd->gd, GQ_ICON_STOP, _("Stop"),
1544 cache_manager_sim_stop_cb, FALSE);
1545 gtk_widget_set_sensitive(cd->button_stop, FALSE);
1547 generic_dialog_add_message(cd->gd, nullptr, _("Create sim. files recursively"), nullptr, FALSE);
1549 hbox = pref_box_new(cd->gd->vbox, FALSE, GTK_ORIENTATION_HORIZONTAL, 0);
1550 pref_spacer(hbox, PREF_PAD_INDENT);
1551 cd->group = pref_box_new(hbox, TRUE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
1553 hbox = pref_box_new(cd->group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
1554 pref_label_new(hbox, _("Folder:"));
1556 label = tab_completion_new(&cd->entry, path, nullptr, nullptr, nullptr, nullptr);
1557 tab_completion_add_select_button(cd->entry,_("Select folder") , TRUE);
1558 gq_gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0);
1559 gtk_widget_show(label);
1561 pref_line(cd->gd->vbox, PREF_PAD_SPACE);
1562 hbox = pref_box_new(cd->gd->vbox, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
1564 cd->progress = gtk_entry_new();
1565 gtk_widget_set_can_focus(cd->progress, FALSE);
1566 gtk_editable_set_editable(GTK_EDITABLE(cd->progress), FALSE);
1567 gq_gtk_entry_set_text(GTK_ENTRY(cd->progress), _("click start to begin"));
1568 gq_gtk_box_pack_start(GTK_BOX(hbox), cd->progress, TRUE, TRUE, 0);
1569 gtk_widget_show(cd->progress);
1571 cd->progress_bar = gtk_progress_bar_new();
1572 gq_gtk_box_pack_start(GTK_BOX(cd->gd->vbox), cd->progress_bar, TRUE, TRUE, 0);
1573 gtk_widget_show(cd->progress_bar);
1575 cd->spinner = gtk_spinner_new();
1576 gq_gtk_box_pack_start(GTK_BOX(hbox), cd->spinner, FALSE, FALSE, 0);
1577 gtk_widget_show(cd->spinner);
1581 gtk_widget_show(cd->gd->dialog);
1584 static void cache_manager_sim_load_cb(GtkWidget *widget, gpointer)
1586 const gchar *path = layout_get_path(nullptr);
1588 if (!path || !*path) path = homedir();
1589 cache_manager_sim_load_dialog(widget, path);
1592 static void cache_manager_cache_maintenance_close_cb(GenericDialog *, gpointer data)
1594 auto cd = static_cast<CacheOpsData *>(data);
1596 if (!gtk_widget_get_sensitive(cd->button_close)) return;
1598 cache_manager_sim_reset(cd);
1599 generic_dialog_close(cd->gd);
1603 static void cache_manager_cache_maintenance_start_cb(GenericDialog *, gpointer data)
1605 auto cd = static_cast<CacheOpsData *>(data);
1611 if (cd->list || !gtk_widget_get_sensitive(cd->button_start)) return;
1614 path = remove_trailing_slash((gq_gtk_entry_get_text(GTK_ENTRY(cd->entry))));
1615 parse_out_relatives(path);
1621 warning_dialog(_("Invalid folder"),
1622 _("The specified folder can not be found."),
1623 GQ_ICON_DIALOG_WARNING, cd->gd->dialog);
1627 log_printf("The specified folder can not be found: \"%s\"\n", path);
1632 cmd_line = g_strdup_printf("%s --cache-maintenance \"%s\"", gq_executable_path, path);
1634 g_spawn_command_line_async(cmd_line, nullptr);
1637 generic_dialog_close(cd->gd);
1638 cache_manager_sim_reset(cd);
1645 static void cache_manager_cache_maintenance_load_dialog(GtkWidget *widget, const gchar *path)
1651 cd = g_new0(CacheOpsData, 1);
1655 cd->gd = generic_dialog_new(_("Background cache maintenance"), "background_cache_maintenance", widget, FALSE, nullptr, cd);
1656 gtk_window_set_default_size(GTK_WINDOW(cd->gd->dialog), PURGE_DIALOG_WIDTH, -1);
1657 cd->gd->cancel_cb = cache_manager_cache_maintenance_close_cb;
1658 cd->button_close = generic_dialog_add_button(cd->gd, GQ_ICON_CLOSE, _("Close"),
1659 cache_manager_cache_maintenance_close_cb, FALSE);
1660 cd->button_start = generic_dialog_add_button(cd->gd, GQ_ICON_OK, _("S_tart"),
1661 cache_manager_cache_maintenance_start_cb, FALSE);
1663 generic_dialog_add_message(cd->gd, nullptr, _("Recursively delete orphaned thumbnails\nand .sim files, and create new\nthumbnails and .sim files"), nullptr, FALSE);
1665 hbox = pref_box_new(cd->gd->vbox, FALSE, GTK_ORIENTATION_HORIZONTAL, 0);
1666 pref_spacer(hbox, PREF_PAD_INDENT);
1667 cd->group = pref_box_new(hbox, TRUE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
1669 hbox = pref_box_new(cd->group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
1670 pref_label_new(hbox, _("Folder:"));
1672 label = tab_completion_new(&cd->entry, path, nullptr, nullptr, nullptr, nullptr);
1673 tab_completion_add_select_button(cd->entry,_("Select folder") , TRUE);
1674 gq_gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0);
1675 gtk_widget_show(label);
1679 gtk_widget_show(cd->gd->dialog);
1682 static void cache_manager_cache_maintenance_load_cb(GtkWidget *widget, gpointer)
1684 const gchar *path = layout_get_path(nullptr);
1686 if (!path || !*path) path = homedir();
1687 cache_manager_cache_maintenance_load_dialog(widget, path);
1690 void cache_manager_show()
1696 GtkSizeGroup *sizegroup;
1701 gtk_window_present(GTK_WINDOW(cache_manager->dialog->dialog));
1705 cache_manager = g_new0(CacheManager, 1);
1707 cache_manager->dialog = generic_dialog_new(_("Cache Maintenance"),
1710 nullptr, cache_manager);
1711 gd = cache_manager->dialog;
1713 gd->cancel_cb = cache_manager_close_cb;
1714 generic_dialog_add_button(gd, GQ_ICON_CLOSE, _("Close"),
1715 cache_manager_close_cb, FALSE);
1716 generic_dialog_add_button(gd, GQ_ICON_HELP, _("Help"),
1717 cache_manager_help_cb, FALSE);
1719 generic_dialog_add_message(gd, nullptr, _("Cache and Data Maintenance"), nullptr, FALSE);
1721 sizegroup = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
1723 group = pref_group_new(gd->vbox, FALSE, _("Geeqie thumbnail and sim. cache"), GTK_ORIENTATION_VERTICAL);
1725 cache_manager_location_label(group, get_thumbnails_cache_dir());
1727 table = pref_table_new(group, 2, 2, FALSE, FALSE);
1729 button = pref_table_button(table, 0, 0, GQ_ICON_CLEAR, _("Clean up"),
1730 G_CALLBACK(cache_manager_main_clean_cb), cache_manager);
1731 gtk_size_group_add_widget(sizegroup, button);
1732 pref_table_label(table, 1, 0, _("Remove orphaned or outdated thumbnails and sim. files."), GTK_ALIGN_START);
1734 button = pref_table_button(table, 0, 1, GQ_ICON_DELETE, _("Clear cache"),
1735 G_CALLBACK(cache_manager_main_clear_cb), cache_manager);
1736 gtk_size_group_add_widget(sizegroup, button);
1737 pref_table_label(table, 1, 1, _("Delete all cached data."), GTK_ALIGN_START);
1740 group = pref_group_new(gd->vbox, FALSE, _("Shared thumbnail cache"), GTK_ORIENTATION_VERTICAL);
1742 path = g_build_filename(get_thumbnails_standard_cache_dir(), NULL);
1743 cache_manager_location_label(group, path);
1746 table = pref_table_new(group, 2, 2, FALSE, FALSE);
1748 button = pref_table_button(table, 0, 0, GQ_ICON_CLEAR, _("Clean up"),
1749 G_CALLBACK(cache_manager_standard_clean_cb), cache_manager);
1750 gtk_size_group_add_widget(sizegroup, button);
1751 pref_table_label(table, 1, 0, _("Remove orphaned or outdated thumbnails."), GTK_ALIGN_START);
1753 button = pref_table_button(table, 0, 1, GQ_ICON_DELETE, _("Clear cache"),
1754 G_CALLBACK(cache_manager_standard_clear_cb), cache_manager);
1755 gtk_size_group_add_widget(sizegroup, button);
1756 pref_table_label(table, 1, 1, _("Delete all cached thumbnails."), GTK_ALIGN_START);
1758 group = pref_group_new(gd->vbox, FALSE, _("Create thumbnails"), GTK_ORIENTATION_VERTICAL);
1760 table = pref_table_new(group, 2, 1, FALSE, FALSE);
1762 button = pref_table_button(table, 0, 1, GQ_ICON_RUN, _("Render"),
1763 G_CALLBACK(cache_manager_render_cb), cache_manager);
1764 gtk_size_group_add_widget(sizegroup, button);
1765 pref_table_label(table, 1, 1, _("Render thumbnails for a specific folder."), GTK_ALIGN_START);
1766 gtk_widget_set_sensitive(group, options->thumbnails.enable_caching);
1768 group = pref_group_new(gd->vbox, FALSE, _("File similarity cache"), GTK_ORIENTATION_VERTICAL);
1770 table = pref_table_new(group, 3, 2, FALSE, FALSE);
1772 button = pref_table_button(table, 0, 0, GQ_ICON_RUN, _("Create"),
1773 G_CALLBACK(cache_manager_sim_load_cb), cache_manager);
1774 gtk_size_group_add_widget(sizegroup, button);
1775 pref_table_label(table, 1, 0, _("Create sim. files recursively."), GTK_ALIGN_START);
1776 gtk_widget_set_sensitive(group, options->thumbnails.enable_caching);
1778 group = pref_group_new(gd->vbox, FALSE, _("Metadata"), GTK_ORIENTATION_VERTICAL);
1780 cache_manager_location_label(group, get_metadata_cache_dir());
1782 table = pref_table_new(group, 2, 1, FALSE, FALSE);
1784 button = pref_table_button(table, 0, 0, GQ_ICON_CLEAR, _("Clean up"),
1785 G_CALLBACK(cache_manager_metadata_clean_cb), cache_manager);
1786 gtk_size_group_add_widget(sizegroup, button);
1787 pref_table_label(table, 1, 0, _("Remove orphaned keywords and comments."), GTK_ALIGN_START);
1789 group = pref_group_new(gd->vbox, FALSE, _("Background cache maintenance"), GTK_ORIENTATION_VERTICAL);
1791 table = pref_table_new(group, 3, 2, FALSE, FALSE);
1793 button = pref_table_button(table, 0, 0, GQ_ICON_RUN, _("Select"),
1794 G_CALLBACK(cache_manager_cache_maintenance_load_cb), cache_manager);
1795 gtk_size_group_add_widget(sizegroup, button);
1796 pref_table_label(table, 1, 0, _("Run cache maintenance as a background job."), GTK_ALIGN_START);
1797 gtk_widget_set_sensitive(group, options->thumbnails.enable_caching);
1799 gtk_widget_show(cache_manager->dialog->dialog);
1801 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */