Mercurial > geeqie.yaz
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 |