comparison src/cache_maint.c @ 9:d907d608745f

Sync to GQview 1.5.9 release. ######## DO NOT BASE ENHANCEMENTS OR TRANSLATION UPDATES ON CODE IN THIS CVS! This CVS is never up to date with current development and is provided solely for reference purposes, please use the latest official release package when making any changes or translation updates. ########
author gqview
date Sat, 26 Feb 2005 00:13:35 +0000
parents
children 31759d770628
comparison
equal deleted inserted replaced
8:e0d0593d519e 9:d907d608745f
1 /*
2 * GQview
3 * (C) 2004 John Ellis
4 *
5 * Author: John Ellis
6 *
7 * This software is released under the GNU General Public License (GNU GPL).
8 * Please read the included file COPYING for more information.
9 * This software comes with no warranty of any kind, use at your own risk!
10 */
11
12 #include "gqview.h"
13 #include "cache_maint.h"
14
15 #include "cache.h"
16 #include "filelist.h"
17 #include "thumb.h"
18 #include "thumb_standard.h"
19 #include "ui_fileops.h"
20 #include "ui_misc.h"
21 #include "ui_spinner.h"
22 #include "ui_tabcomp.h"
23 #include "ui_utildlg.h"
24
25
26 typedef struct _CMData CMData;
27 struct _CMData
28 {
29 GList *list;
30 GList *done_list;
31 gint idle_id;
32 GenericDialog *gd;
33 GtkWidget *entry;
34 GtkWidget *spinner;
35 GtkWidget *button_stop;
36 GtkWidget *button_close;
37 gint clear;
38 gint metadata;
39 };
40
41 #define PURGE_DIALOG_WIDTH 400
42
43
44 /*
45 *-------------------------------------------------------------------
46 * cache maintenance
47 *-------------------------------------------------------------------
48 */
49
50 static gint extension_truncate(gchar *path, const gchar *ext)
51 {
52 gint l;
53 gint el;
54
55 if (!path || !ext) return FALSE;
56
57 l = strlen(path);
58 el = strlen(ext);
59
60 if (l < el || strcmp(path + (l - el), ext) != 0) return FALSE;
61
62 path[l - el] = '\0';
63
64 return TRUE;
65 }
66
67 static gchar *extension_find_dot(gchar *path)
68 {
69 gchar *ptr;
70
71 if (!path || *path == '\0') return NULL;
72
73 ptr = path;
74 while (*ptr != '\0') ptr++;
75
76 while (ptr > path && *ptr != '.') ptr--;
77
78 if (ptr == path) return NULL;
79
80 return ptr;
81 }
82
83 static gint isempty(const gchar *path)
84 {
85 DIR *dp;
86 struct dirent *dir;
87 gchar *pathl;
88
89 pathl = path_from_utf8(path);
90 dp = opendir(pathl);
91 g_free(pathl);
92 if (!dp) return FALSE;
93
94 while ((dir = readdir(dp)) != NULL)
95 {
96 gchar *name = dir->d_name;
97
98 if (dir->d_ino > 0 &&
99 !(name[0] == '.' && (name[1] == '\0' || (name[1] == '.' && name[2] == '\0'))) )
100 {
101 closedir(dp);
102 return FALSE;
103 }
104 }
105
106 closedir(dp);
107 return TRUE;
108 }
109
110 static void cache_maintain_home_close(CMData *cm)
111 {
112 if (cm->idle_id != -1) g_source_remove(cm->idle_id);
113 if (cm->gd) generic_dialog_close(cm->gd);
114 path_list_free(cm->list);
115 g_list_free(cm->done_list);
116 g_free(cm);
117 }
118
119 static void cache_maintain_home_stop(CMData *cm)
120 {
121 if (cm->idle_id != -1)
122 {
123 g_source_remove(cm->idle_id);
124 cm->idle_id = -1;
125 }
126
127 gtk_entry_set_text(GTK_ENTRY(cm->entry), _("done"));
128 spinner_set_interval(cm->spinner, -1);
129
130 gtk_widget_set_sensitive(cm->button_stop, FALSE);
131 gtk_widget_set_sensitive(cm->button_close, TRUE);
132 }
133
134 static gint cache_maintain_home_cb(gpointer data)
135 {
136 CMData *cm = data;
137 GList *dlist = NULL;
138 GList *list = NULL;
139 gchar *path;
140 gint just_done = FALSE;
141 gint still_have_a_file = TRUE;
142 gint base_length;
143 const gchar *cache_folder;
144
145 if (cm->metadata)
146 {
147 cache_folder = GQVIEW_CACHE_RC_METADATA;
148 }
149 else
150 {
151 cache_folder = GQVIEW_CACHE_RC_THUMB;
152 }
153
154 base_length = strlen(homedir()) + strlen("/") + strlen(cache_folder);
155
156 if (!cm->list)
157 {
158 if (debug) printf("purge chk done.\n");
159 cm->idle_id = -1;
160 cache_maintain_home_stop(cm);
161 return FALSE;
162 }
163
164 path = cm->list->data;
165
166 if (debug) printf("purge chk (%d) \"%s\"\n", (cm->clear && !cm->metadata), path);
167
168 if (g_list_find(cm->done_list, path) == NULL)
169 {
170 cm->done_list = g_list_prepend(cm->done_list, path);
171
172 if (path_list(path, &list, &dlist))
173 {
174 GList *work;
175
176 just_done = TRUE;
177 still_have_a_file = FALSE;
178
179 work = list;
180 while (work)
181 {
182 gchar *path_buf = work->data;
183 gchar *dot;
184
185 dot = extension_find_dot(path_buf);
186
187 if (dot) *dot = '\0';
188 if ((!cm->metadata && cm->clear) ||
189 (strlen(path_buf) > base_length && !isfile(path_buf + base_length)) )
190 {
191 if (dot) *dot = '.';
192 if (!unlink_file(path_buf)) printf("failed to delete:%s\n", path_buf);
193 }
194 else
195 {
196 still_have_a_file = TRUE;
197 }
198 work = work->next;
199 }
200 }
201 }
202 path_list_free(list);
203
204 cm->list = g_list_concat(dlist, cm->list);
205
206 if (cm->list && g_list_find(cm->done_list, cm->list->data) != NULL)
207 {
208 /* check if the dir is empty */
209
210 if (cm->list->data == path && just_done)
211 {
212 if (!still_have_a_file && !dlist && cm->list->next && !rmdir_utf8(path))
213 {
214 printf("Unable to delete dir: %s\n", path);
215 }
216 }
217 else
218 {
219 /* must re-check for an empty dir */
220 if (isempty(path) && cm->list->next && !rmdir_utf8(path))
221 {
222 printf("Unable to delete dir: %s\n", path);
223 }
224 }
225
226 path = cm->list->data;
227 cm->done_list = g_list_remove(cm->done_list, path);
228 cm->list = g_list_remove(cm->list, path);
229 g_free(path);
230 }
231
232 if (cm->list)
233 {
234 const gchar *buf;
235
236 path = cm->list->data;
237 if (strlen(path) > base_length)
238 {
239 buf = path + base_length;
240 }
241 else
242 {
243 buf = "...";
244 }
245 gtk_entry_set_text(GTK_ENTRY(cm->entry), buf);
246 }
247
248 return TRUE;
249 }
250
251 static void cache_maintain_home_close_cb(GenericDialog *gd, gpointer data)
252 {
253 CMData *cm = data;
254
255 if (!GTK_WIDGET_SENSITIVE(cm->button_close)) return;
256
257 cache_maintain_home_close(cm);
258 }
259
260 static void cache_maintain_home_stop_cb(GenericDialog *gd, gpointer data)
261 {
262 CMData *cm = data;
263
264 cache_maintain_home_stop(cm);
265 }
266
267 /* sorry for complexity (cm->done_list), but need it to remove empty dirs */
268 void cache_maintain_home(gint metadata, gint clear, GtkWidget *parent)
269 {
270 CMData *cm;
271 GList *dlist = NULL;
272 gchar *base;
273 const gchar *msg;
274 const gchar *cache_folder;
275 GtkWidget *hbox;
276
277 if (metadata)
278 {
279 cache_folder = GQVIEW_CACHE_RC_METADATA;
280 }
281 else
282 {
283 cache_folder = GQVIEW_CACHE_RC_THUMB;
284 }
285
286 base = g_strconcat(homedir(), "/", cache_folder, NULL);
287
288 if (!path_list(base, NULL, &dlist))
289 {
290 g_free(base);
291 return;
292 }
293
294 dlist = g_list_append(dlist, base);
295
296 cm = g_new0(CMData, 1);
297 cm->list = dlist;
298 cm->done_list = NULL;
299 cm->clear = clear;
300 cm->metadata = metadata;
301
302 if (metadata)
303 {
304 msg = _("Removing old metadata...");
305 }
306 else if (clear)
307 {
308 msg = _("Clearing cached thumbnails...");
309 }
310 else
311 {
312 msg = _("Removing old thumbnails...");
313 }
314
315 cm->gd = generic_dialog_new(_("Maintenance"),
316 "GQview", "gqview_maintenance",
317 parent, FALSE,
318 NULL, cm);
319 cm->gd->cancel_cb = cache_maintain_home_close_cb;
320 cm->button_close = generic_dialog_add_button(cm->gd, GTK_STOCK_CLOSE, NULL,
321 cache_maintain_home_close_cb, FALSE);
322 gtk_widget_set_sensitive(cm->button_close, FALSE);
323 cm->button_stop = generic_dialog_add_button(cm->gd, GTK_STOCK_STOP, NULL,
324 cache_maintain_home_stop_cb, FALSE);
325
326 generic_dialog_add_message(cm->gd, NULL, msg, NULL);
327 gtk_window_set_default_size(GTK_WINDOW(cm->gd->dialog), PURGE_DIALOG_WIDTH, -1);
328
329 hbox = gtk_hbox_new(FALSE, 0);
330 gtk_box_pack_start(GTK_BOX(cm->gd->vbox), hbox, FALSE, FALSE, 5);
331 gtk_widget_show(hbox);
332
333 cm->entry = gtk_entry_new();
334 GTK_WIDGET_UNSET_FLAGS(cm->entry, GTK_CAN_FOCUS);
335 gtk_editable_set_editable(GTK_EDITABLE(cm->entry), FALSE);
336 gtk_box_pack_start(GTK_BOX(hbox), cm->entry, TRUE, TRUE, 0);
337 gtk_widget_show(cm->entry);
338
339 cm->spinner = spinner_new(NULL, SPINNER_SPEED);
340 gtk_box_pack_start(GTK_BOX(hbox), cm->spinner, FALSE, FALSE, 0);
341 gtk_widget_show(cm->spinner);
342
343 gtk_widget_show(cm->gd->dialog);
344
345 cm->idle_id = g_idle_add(cache_maintain_home_cb, cm);
346 }
347
348 /* This checks all files in ~/.gqview/thumbnails and
349 * removes them if thay have no source counterpart.
350 * (this assumes all cache files have an extension of 4 chars including '.')
351 */
352 gint cache_maintain_home_dir(const gchar *dir, gint recursive, gint clear)
353 {
354 gchar *base;
355 gint base_length;
356 GList *dlist = NULL;
357 GList *flist = NULL;
358 gint still_have_a_file = FALSE;
359
360 if (debug) printf("maintainance check: %s\n", dir);
361
362 base_length = strlen(homedir()) + strlen("/") + strlen(GQVIEW_CACHE_RC_THUMB);
363 base = g_strconcat(homedir(), "/", GQVIEW_CACHE_RC_THUMB, dir, NULL);
364
365 if (path_list(base, &flist, &dlist))
366 {
367 GList *work;
368
369 work = dlist;
370 while(work)
371 {
372 gchar *path = work->data;
373 if (recursive && strlen(path) > base_length &&
374 !cache_maintain_home_dir(path + base_length, recursive, clear))
375 {
376 if (debug) printf("Deleting thumb dir: %s\n", path);
377 if (!rmdir_utf8(path))
378 {
379 printf("Unable to delete dir: %s\n", path);
380 }
381 }
382 else
383 {
384 still_have_a_file = TRUE;
385 }
386 work = work->next;
387 }
388
389 work = flist;
390 while (work)
391 {
392 gchar *path = work->data;
393 gchar *dot;
394
395 dot = extension_find_dot(path);
396
397 if (dot) *dot = '\0';
398 if (clear ||
399 (strlen(path) > base_length && !isfile(path + base_length)) )
400 {
401 if (dot) *dot = '.';
402 if (!unlink_file(path)) printf("failed to delete:%s\n", path);
403 }
404 else
405 {
406 still_have_a_file = TRUE;
407 }
408
409 work = work->next;
410 }
411 }
412
413 path_list_free(dlist);
414 path_list_free(flist);
415 g_free(base);
416
417 return still_have_a_file;
418 }
419
420 /* This checks relative caches in dir/.thumbnails and
421 * removes them if they have no source counterpart.
422 */
423 gint cache_maintain_dir(const gchar *dir, gint recursive, gint clear)
424 {
425 GList *list = NULL;
426 gchar *cachedir;
427 gint still_have_a_file = FALSE;
428 GList *work;
429
430 cachedir = g_strconcat(dir, "/", GQVIEW_CACHE_LOCAL_THUMB, NULL);
431
432 path_list(cachedir, &list, NULL);
433 work = list;
434
435 while (work)
436 {
437 const gchar *path;
438 gchar *source;
439
440 path = work->data;
441 work = work->next;
442
443 source = g_strconcat(dir, "/", filename_from_path(path), NULL);
444
445 if (clear ||
446 extension_truncate(source, GQVIEW_CACHE_EXT_THUMB) ||
447 extension_truncate(source, GQVIEW_CACHE_EXT_SIM))
448 {
449 if (!clear && isfile(source))
450 {
451 still_have_a_file = TRUE;
452 }
453 else
454 {
455 if (!unlink_file(path))
456 {
457 if (debug) printf("Failed to remove cache file %s\n", path);
458 still_have_a_file = TRUE;
459 }
460 }
461 }
462 else
463 {
464 still_have_a_file = TRUE;
465 }
466 g_free(source);
467 }
468
469 path_list_free(list);
470 g_free(cachedir);
471
472 if (recursive)
473 {
474 list = NULL;
475
476 path_list(dir, NULL, &list);
477 work = list;
478 while (work)
479 {
480 const gchar *path = work->data;
481 work = work->next;
482
483 still_have_a_file |= cache_maintain_dir(path, recursive, clear);
484 }
485
486 path_list_free(list);
487 }
488
489 return still_have_a_file;
490 }
491
492 static void cache_file_move(const gchar *src, const gchar *dest)
493 {
494 if (!dest || !src || !isfile(src)) return;
495
496 if (!move_file(src, dest))
497 {
498 if (debug) printf("Failed to move cache file %s\nto %s\n", src, dest);
499 /* we remove it anyway - it's stale */
500 unlink_file(src);
501 }
502 }
503
504 void cache_maint_moved(const gchar *src, const gchar *dest)
505 {
506 gchar *base;
507 mode_t mode = 0755;
508
509 if (!src || !dest) return;
510
511 base = cache_get_location(CACHE_TYPE_THUMB, dest, FALSE, &mode);
512 if (cache_ensure_dir_exists(base, mode))
513 {
514 gchar *buf;
515 gchar *d;
516
517 buf = cache_find_location(CACHE_TYPE_THUMB, src);
518 d = cache_get_location(CACHE_TYPE_THUMB, dest, TRUE, NULL);
519 cache_file_move(buf, d);
520 g_free(d);
521 g_free(buf);
522
523 buf = cache_find_location(CACHE_TYPE_SIM, src);
524 d = cache_get_location(CACHE_TYPE_SIM, dest, TRUE, NULL);
525 cache_file_move(buf, d);
526 g_free(d);
527 g_free(buf);
528 }
529 else
530 {
531 printf("Failed to create cache dir for move %s\n", base);
532 }
533 g_free(base);
534
535 base = cache_get_location(CACHE_TYPE_METADATA, dest, FALSE, &mode);
536 if (cache_ensure_dir_exists(base, mode))
537 {
538 gchar *buf;
539 gchar *d;
540
541 buf = cache_find_location(CACHE_TYPE_METADATA, src);
542 d = cache_get_location(CACHE_TYPE_METADATA, dest, TRUE, NULL);
543 cache_file_move(buf, d);
544 g_free(d);
545 g_free(buf);
546 }
547 g_free(base);
548
549 if (enable_thumb_caching && thumbnail_spec_standard) thumb_std_maint_moved(src, dest);
550 }
551
552 static void cache_file_remove(const gchar *path)
553 {
554 if (path && isfile(path) && !unlink_file(path))
555 {
556 if (debug) printf("Failed to remove cache file %s\n", path);
557 }
558 }
559
560 void cache_maint_removed(const gchar *source)
561 {
562 gchar *buf;
563
564 buf = cache_find_location(CACHE_TYPE_THUMB, source);
565 cache_file_remove(buf);
566 g_free(buf);
567
568 buf = cache_find_location(CACHE_TYPE_SIM, source);
569 cache_file_remove(buf);
570 g_free(buf);
571
572 buf = cache_find_location(CACHE_TYPE_METADATA, source);
573 cache_file_remove(buf);
574 g_free(buf);
575
576 if (enable_thumb_caching && thumbnail_spec_standard) thumb_std_maint_removed(source);
577 }
578
579 void cache_maint_copied(const gchar *src, const gchar *dest)
580 {
581 gchar *dest_base;
582 gchar *src_cache;
583 mode_t mode = 0755;
584
585 src_cache = cache_find_location(CACHE_TYPE_METADATA, src);
586 if (!src_cache) return;
587
588 dest_base = cache_get_location(CACHE_TYPE_METADATA, dest, FALSE, &mode);
589 if (cache_ensure_dir_exists(dest_base, mode))
590 {
591 gchar *path;
592
593 path = cache_get_location(CACHE_TYPE_METADATA, dest, TRUE, NULL);
594 if (!copy_file(src_cache, path))
595 {
596 if (debug) printf("failed to copy metadata %s to %s\n", src_cache, path);
597 }
598 g_free(path);
599 }
600
601 g_free(dest_base);
602 g_free(src_cache);
603 }
604
605 /*
606 *-------------------------------------------------------------------
607 * new cache maintenance utilities
608 *-------------------------------------------------------------------
609 */
610
611 typedef struct _CacheManager CacheManager;
612 struct _CacheManager
613 {
614 GenericDialog *dialog;
615 GtkWidget *folder_entry;
616 GtkWidget *progress;
617
618 GList *list_todo;
619
620 gint count_total;
621 gint count_done;
622 };
623
624 typedef struct _CleanData CleanData;
625 struct _CleanData
626 {
627 GenericDialog *gd;
628 ThumbLoaderStd *tl;
629
630 GList *list;
631 GList *list_dir;
632
633 gint days;
634 gint clear;
635
636 GtkWidget *button_close;
637 GtkWidget *button_stop;
638 GtkWidget *button_start;
639 GtkWidget *progress;
640 GtkWidget *spinner;
641
642 GtkWidget *group;
643 GtkWidget *entry;
644
645 gint count_total;
646 gint count_done;
647
648 gint local;
649 gint recurse;
650
651 gint idle_id;
652 };
653
654 static void cache_manager_render_reset(CleanData *cd)
655 {
656 path_list_free(cd->list);
657 cd->list = NULL;
658
659 path_list_free(cd->list_dir);
660 cd->list_dir = NULL;
661
662 thumb_loader_free((ThumbLoader *)cd->tl);
663 cd->tl = NULL;
664 }
665
666 static void cache_manager_render_close_cb(GenericDialog *fd, gpointer data)
667 {
668 CleanData *cd = data;
669
670 if (!GTK_WIDGET_SENSITIVE(cd->button_close)) return;
671
672 cache_manager_render_reset(cd);
673 generic_dialog_close(cd->gd);
674 g_free(cd);
675 }
676
677 static void cache_manager_render_finish(CleanData *cd)
678 {
679 cache_manager_render_reset(cd);
680
681 gtk_entry_set_text(GTK_ENTRY(cd->progress), _("done"));
682 spinner_set_interval(cd->spinner, -1);
683
684 gtk_widget_set_sensitive(cd->group, TRUE);
685 gtk_widget_set_sensitive(cd->button_start, TRUE);
686 gtk_widget_set_sensitive(cd->button_stop, FALSE);
687 gtk_widget_set_sensitive(cd->button_close, TRUE);
688 }
689
690 static void cache_manager_render_stop_cb(GenericDialog *fd, gpointer data)
691 {
692 CleanData *cd = data;
693
694 cache_manager_render_finish(cd);
695 }
696
697 static void cache_manager_render_folder(CleanData *cd, const gchar *path)
698 {
699 GList *list_d = NULL;
700 GList *list_f = NULL;
701
702 if (cd->recurse)
703 {
704 path_list(path, &list_f, &list_d);
705 }
706 else
707 {
708 path_list(path, &list_f, NULL);
709 }
710
711 list_f = path_list_filter(list_f, FALSE);
712 list_d = path_list_filter(list_d, TRUE);
713
714 cd->list = g_list_concat(list_f, cd->list);
715 cd->list_dir = g_list_concat(list_d, cd->list_dir);
716 }
717
718 static gint cache_manager_render_file(CleanData *cd);
719
720 static void cache_manager_render_thumb_done_cb(ThumbLoader *tl, gpointer data)
721 {
722 CleanData *cd = data;
723
724 thumb_loader_free((ThumbLoader *)cd->tl);
725 cd->tl = NULL;
726
727 while (cache_manager_render_file(cd));
728 }
729
730 static gint cache_manager_render_file(CleanData *cd)
731 {
732 if (cd->list)
733 {
734 gchar *path;
735 gint success;
736
737 path = cd->list->data;
738 cd->list = g_list_remove(cd->list, path);
739
740 cd->tl = (ThumbLoaderStd *)thumb_loader_new(thumb_max_width, thumb_max_height);
741 thumb_loader_set_callbacks((ThumbLoader *)cd->tl,
742 cache_manager_render_thumb_done_cb,
743 cache_manager_render_thumb_done_cb,
744 NULL, cd);
745 thumb_loader_set_cache((ThumbLoader *)cd->tl, TRUE, cd->local, TRUE);
746 success = thumb_loader_start((ThumbLoader *)cd->tl, path);
747 if (success)
748 {
749 gtk_entry_set_text(GTK_ENTRY(cd->progress), path);
750 }
751 else
752 {
753 thumb_loader_free((ThumbLoader *)cd->tl);
754 cd->tl = NULL;
755 }
756
757 g_free(path);
758
759 return (!success);
760 }
761 else if (cd->list_dir)
762 {
763 gchar *path;
764
765 path = cd->list_dir->data;
766 cd->list_dir = g_list_remove(cd->list_dir, path);
767
768 cache_manager_render_folder(cd, path);
769
770 g_free(path);
771
772 return TRUE;
773 }
774
775 cache_manager_render_finish(cd);
776
777 return FALSE;
778 }
779
780 static void cache_manager_render_start_cb(GenericDialog *fd, gpointer data)
781 {
782 CleanData *cd = data;
783 gchar *path;
784
785 if (cd->list || !GTK_WIDGET_SENSITIVE(cd->button_start)) return;
786
787 path = remove_trailing_slash((gtk_entry_get_text(GTK_ENTRY(cd->entry))));
788 parse_out_relatives(path);
789
790 if (!isdir(path))
791 {
792 warning_dialog(_("Invalid folder"),
793 _("The specified folder can not be found."),
794 GTK_STOCK_DIALOG_WARNING, cd->gd->dialog);
795 }
796 else
797 {
798 gtk_widget_set_sensitive(cd->group, FALSE);
799 gtk_widget_set_sensitive(cd->button_start, FALSE);
800 gtk_widget_set_sensitive(cd->button_stop, TRUE);
801 gtk_widget_set_sensitive(cd->button_close, FALSE);
802
803 spinner_set_interval(cd->spinner, SPINNER_SPEED);
804
805 cache_manager_render_folder(cd, path);
806 while (cache_manager_render_file(cd));
807 }
808
809 g_free(path);
810 }
811
812 static void cache_manager_render_dialog(GtkWidget *widget, const gchar *path)
813 {
814 CleanData *cd;
815 GtkWidget *hbox;
816 GtkWidget *label;
817 GtkWidget *button;
818
819 cd = g_new0(CleanData, 1);
820
821 cd->gd = generic_dialog_new(_("Create thumbnails"),
822 "GQview", "create_thumbnails",
823 widget, FALSE,
824 NULL, cd);
825 gtk_window_set_default_size(GTK_WINDOW(cd->gd->dialog), PURGE_DIALOG_WIDTH, -1);
826 cd->gd->cancel_cb = cache_manager_render_close_cb;
827 cd->button_close = generic_dialog_add_button(cd->gd, GTK_STOCK_CLOSE, NULL,
828 cache_manager_render_close_cb, FALSE);
829 cd->button_start = generic_dialog_add_button(cd->gd, GTK_STOCK_OK, _("S_tart"),
830 cache_manager_render_start_cb, FALSE);
831 cd->button_stop = generic_dialog_add_button(cd->gd, GTK_STOCK_STOP, NULL,
832 cache_manager_render_stop_cb, FALSE);
833 gtk_widget_set_sensitive(cd->button_stop, FALSE);
834
835 generic_dialog_add_message(cd->gd, NULL, _("Create thumbnails"), NULL);
836
837 hbox = pref_box_new(cd->gd->vbox, FALSE, GTK_ORIENTATION_HORIZONTAL, 0);
838 pref_spacer(hbox, PREF_PAD_INDENT);
839 cd->group = pref_box_new(hbox, TRUE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
840
841 hbox = pref_box_new(cd->group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
842 pref_label_new(hbox, _("Folder:"));
843
844 label = tab_completion_new(&cd->entry, path, NULL, NULL);
845 tab_completion_add_select_button(cd->entry,_("Select folder") , TRUE);
846 gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0);
847 gtk_widget_show(label);
848
849 pref_checkbox_new_int(cd->group, _("Include subfolders"), FALSE, &cd->recurse);
850 button = pref_checkbox_new_int(cd->group, _("Store thumbnails local to source images"), FALSE, &cd->local);
851 gtk_widget_set_sensitive(button, thumbnail_spec_standard);
852
853 pref_line(cd->gd->vbox, PREF_PAD_SPACE);
854 hbox = pref_box_new(cd->gd->vbox, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
855
856 cd->progress = gtk_entry_new();
857 GTK_WIDGET_UNSET_FLAGS(cd->progress, GTK_CAN_FOCUS);
858 gtk_editable_set_editable(GTK_EDITABLE(cd->progress), FALSE);
859 gtk_entry_set_text(GTK_ENTRY(cd->progress), _("click start to begin"));
860 gtk_box_pack_start(GTK_BOX(hbox), cd->progress, TRUE, TRUE, 0);
861 gtk_widget_show(cd->progress);
862
863 cd->spinner = spinner_new(NULL, -1);
864 gtk_box_pack_start(GTK_BOX(hbox), cd->spinner, FALSE, FALSE, 0);
865 gtk_widget_show(cd->spinner);
866
867 cd->list = NULL;
868
869 gtk_widget_show(cd->gd->dialog);
870 }
871
872
873
874
875 static void cache_manager_standard_clean_close_cb(GenericDialog *gd, gpointer data)
876 {
877 CleanData *cd = data;
878
879 if (!GTK_WIDGET_SENSITIVE(cd->button_close)) return;
880
881 generic_dialog_close(cd->gd);
882
883 thumb_loader_std_thumb_file_validate_cancel(cd->tl);
884 path_list_free(cd->list);
885 g_free(cd);
886 }
887
888 static void cache_manager_standard_clean_done(CleanData *cd)
889 {
890 gtk_widget_set_sensitive(cd->button_stop, FALSE);
891 gtk_widget_set_sensitive(cd->button_close, TRUE);
892
893 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(cd->progress), 1.0);
894 gtk_progress_bar_set_text(GTK_PROGRESS_BAR(cd->progress), _("done"));
895
896 if (cd->idle_id != -1)
897 {
898 g_source_remove(cd->idle_id);
899 cd->idle_id = -1;
900 }
901
902 thumb_loader_std_thumb_file_validate_cancel(cd->tl);
903 cd->tl = NULL;
904
905 path_list_free(cd->list);
906 cd->list = NULL;
907 }
908
909 static void cache_manager_standard_clean_stop_cb(GenericDialog *gd, gpointer data)
910 {
911 CleanData *cd = data;
912
913 cache_manager_standard_clean_done(cd);
914 }
915
916 static gint cache_manager_standard_clean_clear_cb(gpointer data)
917 {
918 CleanData *cd = data;
919
920 if (cd->list)
921 {
922 gchar *next_path;
923
924 next_path = cd->list->data;
925 cd->list = g_list_remove(cd->list, next_path);
926
927 if (debug) printf("thumb removed: %s\n", next_path);
928
929 unlink_file(next_path);
930 g_free(next_path);
931
932 cd->count_done++;
933 if (cd->count_total != 0)
934 {
935 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(cd->progress),
936 (gdouble)cd->count_done / cd->count_total);
937 }
938
939 return TRUE;
940 }
941
942 cd->idle_id = -1;
943 cache_manager_standard_clean_done(cd);
944 return FALSE;
945 }
946
947 static void cache_manager_standard_clean_valid_cb(const gchar *path, gint valid, gpointer data)
948 {
949 CleanData *cd = data;
950
951 if (path)
952 {
953 if (!valid)
954 {
955 if (debug) printf("thumb cleaned: %s\n", path);
956 unlink_file(path);
957 }
958
959 cd->count_done++;
960 if (cd->count_total != 0)
961 {
962 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(cd->progress),
963 (gdouble)cd->count_done / cd->count_total);
964 }
965 }
966
967 cd->tl = NULL;
968 if (cd->list)
969 {
970 gchar *next_path;
971
972 next_path = cd->list->data;
973 cd->list = g_list_remove(cd->list, next_path);
974
975 cd->tl = thumb_loader_std_thumb_file_validate(next_path, cd->days,
976 cache_manager_standard_clean_valid_cb, cd);
977 g_free(next_path);
978 }
979 else
980 {
981 cache_manager_standard_clean_done(cd);
982 }
983 }
984
985 static void cache_manager_standard_clean_start_cb(GenericDialog *gd, gpointer data)
986 {
987 CleanData *cd = data;
988 GList *list;
989 gchar *path;
990
991 if (cd->list || !GTK_WIDGET_SENSITIVE(cd->button_start)) return;
992
993 gtk_widget_set_sensitive(cd->button_start, FALSE);
994 gtk_widget_set_sensitive(cd->button_stop, TRUE);
995 gtk_widget_set_sensitive(cd->button_close, FALSE);
996
997 gtk_progress_bar_set_text(GTK_PROGRESS_BAR(cd->progress), _("running..."));
998
999 path = g_strconcat(homedir(), "/", THUMB_FOLDER, "/", THUMB_FOLDER_NORMAL, NULL);
1000 list = NULL;
1001 path_list(path, &list, NULL);
1002 cd->list = list;
1003 g_free(path);
1004
1005 path = g_strconcat(homedir(), "/", THUMB_FOLDER, "/", THUMB_FOLDER_LARGE, NULL);
1006 list = NULL;
1007 path_list(path, &list, NULL);
1008 cd->list = g_list_concat(cd->list, list);
1009 g_free(path);
1010
1011 path = g_strconcat(homedir(), "/", THUMB_FOLDER, "/", THUMB_FOLDER_FAIL, NULL);
1012 list = NULL;
1013 path_list(path, &list, NULL);
1014 cd->list = g_list_concat(cd->list, list);
1015 g_free(path);
1016
1017 cd->count_total = g_list_length(cd->list);
1018 cd->count_done = 0;
1019
1020 /* start iterating */
1021 if (cd->clear)
1022 {
1023 cd->idle_id = g_idle_add(cache_manager_standard_clean_clear_cb, cd);
1024 }
1025 else
1026 {
1027 cache_manager_standard_clean_valid_cb(NULL, TRUE, cd);
1028 }
1029 }
1030
1031 static void cache_manager_standard_process(GtkWidget *widget, gint clear)
1032 {
1033 CleanData *cd;
1034 const gchar *stock_id;
1035 const gchar *msg;
1036
1037 cd = g_new0(CleanData, 1);
1038 cd->clear = clear;
1039
1040 if (clear)
1041 {
1042 stock_id = GTK_STOCK_DELETE;
1043 msg = _("Clearing thumbnails...");
1044 }
1045 else
1046 {
1047 stock_id = GTK_STOCK_CLEAR;
1048 msg = _("Removing old thumbnails...");
1049 }
1050
1051 cd->gd = generic_dialog_new(_("Maintenance"),
1052 "GQview", "standard_maintenance",
1053 widget, FALSE,
1054 NULL, cd);
1055 cd->gd->cancel_cb = cache_manager_standard_clean_close_cb;
1056 cd->button_close = generic_dialog_add_button(cd->gd, GTK_STOCK_CLOSE, NULL,
1057 cache_manager_standard_clean_close_cb, FALSE);
1058 cd->button_start = generic_dialog_add_button(cd->gd, GTK_STOCK_OK, _("S_tart"),
1059 cache_manager_standard_clean_start_cb, FALSE);
1060 cd->button_stop = generic_dialog_add_button(cd->gd, GTK_STOCK_STOP, NULL,
1061 cache_manager_standard_clean_stop_cb, FALSE);
1062 gtk_widget_set_sensitive(cd->button_stop, FALSE);
1063
1064 generic_dialog_add_message(cd->gd, stock_id, msg, NULL);
1065
1066 cd->progress = gtk_progress_bar_new();
1067 gtk_progress_bar_set_text(GTK_PROGRESS_BAR(cd->progress), _("click start to begin"));
1068 gtk_box_pack_start(GTK_BOX(cd->gd->vbox), cd->progress, FALSE, FALSE, 0);
1069 gtk_widget_show(cd->progress);
1070
1071 cd->days = 30;
1072 cd->tl = NULL;
1073 cd->idle_id = -1;
1074
1075 gtk_widget_show(cd->gd->dialog);
1076 }
1077
1078 static void cache_manager_standard_clean_cb(GtkWidget *widget, gpointer data)
1079 {
1080 cache_manager_standard_process(widget, FALSE);
1081 }
1082
1083 static void cache_manager_standard_clear_cb(GtkWidget *widget, gpointer data)
1084 {
1085 cache_manager_standard_process(widget, TRUE);
1086 }
1087
1088
1089 static void cache_manager_gqview_clean_cb(GtkWidget *widget, gpointer data)
1090 {
1091 cache_maintain_home(FALSE, FALSE, widget);
1092 }
1093
1094
1095 static void dummy_cancel_cb(GenericDialog *gd, gpointer data)
1096 {
1097 /* no op, only so cancel button appears */
1098 }
1099
1100 static void cache_manager_gqview_clear_ok_cb(GenericDialog *gd, gpointer data)
1101 {
1102 cache_maintain_home(FALSE, TRUE, NULL);
1103 }
1104
1105 void cache_manager_gqview_clear_confirm(GtkWidget *parent)
1106 {
1107 GenericDialog *gd;
1108
1109 gd = generic_dialog_new(_("Clear cache"),
1110 "GQview", "clear_cache", parent, TRUE,
1111 dummy_cancel_cb, NULL);
1112 generic_dialog_add_message(gd, GTK_STOCK_DIALOG_QUESTION, _("Clear cache"),
1113 _("This will remove all thumbnails that have\nbeen saved to disk, continue?"));
1114 generic_dialog_add_button(gd, GTK_STOCK_OK, NULL, cache_manager_gqview_clear_ok_cb, TRUE);
1115
1116 gtk_widget_show(gd->dialog);
1117 }
1118
1119 static void cache_manager_gqview_clear_cb(GtkWidget *widget, gpointer data)
1120 {
1121 cache_manager_gqview_clear_confirm(widget);
1122 }
1123
1124 static void cache_manager_render_cb(GtkWidget *widget, gpointer data)
1125 {
1126 cache_manager_render_dialog(widget, homedir());
1127 }
1128
1129 static void cache_manager_metadata_clean_cb(GtkWidget *widget, gpointer data)
1130 {
1131 cache_maintain_home(TRUE, FALSE, widget);
1132 }
1133
1134
1135 static CacheManager *cache_manager = NULL;
1136
1137 static void cache_manager_close_cb(GenericDialog *gd, gpointer data)
1138 {
1139 generic_dialog_close(gd);
1140
1141 g_free(cache_manager);
1142 cache_manager = NULL;
1143 }
1144
1145 void cache_manager_show(void)
1146 {
1147 GenericDialog *gd;
1148 GtkWidget *group;
1149 GtkWidget *button;
1150 GtkWidget *label;
1151 GtkWidget *table;
1152 GtkSizeGroup *sizegroup;
1153 gchar *buf;
1154
1155 if (cache_manager)
1156 {
1157 gtk_window_present(GTK_WINDOW(cache_manager->dialog->dialog));
1158 return;
1159 }
1160
1161 cache_manager = g_new0(CacheManager, 1);
1162
1163 cache_manager->dialog = generic_dialog_new(_("Cache Maintenance - GQview"),
1164 "GQiew", "cache_manager",
1165 NULL, FALSE,
1166 NULL, cache_manager);
1167 gd = cache_manager->dialog;
1168
1169 gd->cancel_cb = cache_manager_close_cb;
1170 generic_dialog_add_button(gd, GTK_STOCK_CLOSE, NULL,
1171 cache_manager_close_cb, FALSE);
1172
1173 generic_dialog_add_message(gd, NULL, _("Cache and Data Maintenance"), NULL);
1174
1175 sizegroup = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
1176
1177 group = pref_group_new(gd->vbox, FALSE, _("GQview thumbnail cache"), GTK_ORIENTATION_VERTICAL);
1178
1179 buf = g_strconcat(_("Location:"), " ", homedir(), "/", GQVIEW_CACHE_RC_THUMB, NULL);
1180 label = pref_label_new(group, buf);
1181 gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
1182 g_free(buf);
1183
1184 table = pref_table_new(group, 2, 2, FALSE, FALSE);
1185
1186 button = pref_table_button(table, 0, 0, GTK_STOCK_CLEAR, _("Clean up"), FALSE,
1187 G_CALLBACK(cache_manager_gqview_clean_cb), cache_manager);
1188 gtk_size_group_add_widget(sizegroup, button);
1189 pref_table_label(table, 1, 0, _("Remove orphaned or outdated thumbnails."), 0.0);
1190
1191 button = pref_table_button(table, 0, 1, GTK_STOCK_DELETE, _("Clear cache"), FALSE,
1192 G_CALLBACK(cache_manager_gqview_clear_cb), cache_manager);
1193 gtk_size_group_add_widget(sizegroup, button);
1194 pref_table_label(table, 1, 1, _("Delete all cached thumbnails."), 0.0);
1195
1196
1197 group = pref_group_new(gd->vbox, FALSE, _("Shared thumbnail cache"), GTK_ORIENTATION_VERTICAL);
1198
1199 buf = g_strconcat(_("Location:"), " ", homedir(), "/", THUMB_FOLDER, NULL);
1200 label = pref_label_new(group, buf);
1201 gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
1202 g_free(buf);
1203
1204 table = pref_table_new(group, 2, 2, FALSE, FALSE);
1205
1206 button = pref_table_button(table, 0, 0, GTK_STOCK_CLEAR, _("Clean up"), FALSE,
1207 G_CALLBACK(cache_manager_standard_clean_cb), cache_manager);
1208 gtk_size_group_add_widget(sizegroup, button);
1209 pref_table_label(table, 1, 0, _("Remove orphaned or outdated thumbnails."), 0.0);
1210
1211 button = pref_table_button(table, 0, 1, GTK_STOCK_DELETE, _("Clear cache"), FALSE,
1212 G_CALLBACK(cache_manager_standard_clear_cb), cache_manager);
1213 gtk_size_group_add_widget(sizegroup, button);
1214 pref_table_label(table, 1, 1, _("Delete all cached thumbnails."), 0.0);
1215
1216 group = pref_group_new(gd->vbox, FALSE, _("Create thumbnails"), GTK_ORIENTATION_VERTICAL);
1217
1218 table = pref_table_new(group, 2, 1, FALSE, FALSE);
1219
1220 button = pref_table_button(table, 0, 1, GTK_STOCK_EXECUTE, _("Render"), FALSE,
1221 G_CALLBACK(cache_manager_render_cb), cache_manager);
1222 gtk_size_group_add_widget(sizegroup, button);
1223 pref_table_label(table, 1, 1, _("Render thumbnails for a specific folder."), 0.0);
1224
1225 group = pref_group_new(gd->vbox, FALSE, _("Metadata"), GTK_ORIENTATION_VERTICAL);
1226
1227 buf = g_strconcat(_("Location:"), " ", homedir(), "/", GQVIEW_CACHE_RC_METADATA, NULL);
1228 label = pref_label_new(group, buf);
1229 gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
1230 g_free(buf);
1231
1232 table = pref_table_new(group, 2, 1, FALSE, FALSE);
1233
1234 button = pref_table_button(table, 0, 0, GTK_STOCK_CLEAR, _("Clean up"), FALSE,
1235 G_CALLBACK(cache_manager_metadata_clean_cb), cache_manager);
1236 gtk_size_group_add_widget(sizegroup, button);
1237 pref_table_label(table, 1, 0, _("Remove orphaned keywords and comments."), 0.0);
1238
1239 gtk_widget_show(cache_manager->dialog->dialog);
1240 }
1241