Mercurial > geeqie
annotate src/collect-io.c @ 480:805c3258d228
Make histogram depends on image window not layout window.
It simplifies the code, and make more sense.
author | zas_ |
---|---|
date | Tue, 22 Apr 2008 08:34:30 +0000 |
parents | 48c8e49b571c |
children | dead6fb690c5 |
rev | line source |
---|---|
9 | 1 /* |
196 | 2 * Geeqie |
9 | 3 * (C) 2004 John Ellis |
475 | 4 * Copyright (C) 2008 The Geeqie Team |
9 | 5 * |
6 * Author: John Ellis | |
7 * | |
8 * This software is released under the GNU General Public License (GNU GPL). | |
9 * Please read the included file COPYING for more information. | |
10 * This software comes with no warranty of any kind, use at your own risk! | |
11 */ | |
12 | |
13 | |
281 | 14 #include "main.h" |
9 | 15 #include "collect-io.h" |
16 | |
17 #include "collect.h" | |
312 | 18 #include "filelist.h" |
9 | 19 #include "layout_util.h" |
20 #include "rcfile.h" | |
312 | 21 #include "secure_save.h" |
9 | 22 #include "thumb.h" |
23 #include "ui_fileops.h" | |
24 | |
25 | |
288
d1f74154463e
Replace occurences of Geeqie / geeqie by constants defined in main.h.
zas_
parents:
283
diff
changeset
|
26 #define GQ_COLLECTION_MARKER "#" GQ_APPNAME |
9 | 27 |
283 | 28 #define GQ_COLLECTION_FAIL_MIN 300 |
29 #define GQ_COLLECTION_FAIL_PERCENT 98 | |
360
822040a51249
Increase collection_load() buffer size and do not activate
zas_
parents:
359
diff
changeset
|
30 #define GQ_COLLECTION_READ_BUFSIZE 4096 |
9 | 31 |
138 | 32 typedef struct _CollectManagerEntry CollectManagerEntry; |
9 | 33 |
34 static void collection_load_thumb_step(CollectionData *cd); | |
138 | 35 static gint collection_save_private(CollectionData *cd, const gchar *path); |
36 | |
37 static CollectManagerEntry *collect_manager_get_entry(const gchar *path); | |
38 static void collect_manager_entry_reset(CollectManagerEntry *entry); | |
235 | 39 static gint collect_manager_process_action(CollectManagerEntry *entry, gchar **path_ptr); |
9 | 40 |
41 | |
42 static gint scan_geometry(gchar *buffer, gint *x, gint *y, gint *w, gint *h) | |
43 { | |
44 gint nx, ny, nw, nh; | |
45 | |
46 if(sscanf(buffer, "%d %d %d %d", &nx, &ny, &nw, &nh) != 4) return FALSE; | |
47 | |
48 *x = nx; | |
49 *y = ny; | |
50 *w = nw; | |
51 *h = nh; | |
52 | |
53 return TRUE; | |
54 } | |
55 | |
358 | 56 static gint collection_load_private(CollectionData *cd, const gchar *path, CollectionLoadFlags flags) |
9 | 57 { |
360
822040a51249
Increase collection_load() buffer size and do not activate
zas_
parents:
359
diff
changeset
|
58 gchar s_buf[GQ_COLLECTION_READ_BUFSIZE]; |
9 | 59 FILE *f; |
60 gchar *pathl; | |
361
e0295af4f716
collection_load(): replace official by limit_failures (and
zas_
parents:
360
diff
changeset
|
61 gint limit_failures = TRUE; |
9 | 62 gint success = TRUE; |
365 | 63 gint has_official_header = FALSE; |
64 gint has_geometry_header = FALSE; | |
65 gint has_gqview_header = FALSE; | |
66 gint need_header = TRUE; | |
9 | 67 guint total = 0; |
68 guint fail = 0; | |
138 | 69 gboolean changed = FALSE; |
70 CollectManagerEntry *entry = NULL; | |
366
ce00494827e2
collection_load(): use booleans and always count failures (for debug).
zas_
parents:
365
diff
changeset
|
71 guint flush = !!(flags & COLLECTION_LOAD_FLUSH); |
ce00494827e2
collection_load(): use booleans and always count failures (for debug).
zas_
parents:
365
diff
changeset
|
72 guint append = !!(flags & COLLECTION_LOAD_APPEND); |
ce00494827e2
collection_load(): use booleans and always count failures (for debug).
zas_
parents:
365
diff
changeset
|
73 guint only_geometry = !!(flags & COLLECTION_LOAD_GEOMETRY); |
9 | 74 |
359
96fb24f948b7
Merge collection_load_only_geometry() into collection_load().
zas_
parents:
358
diff
changeset
|
75 if (!only_geometry) |
96fb24f948b7
Merge collection_load_only_geometry() into collection_load().
zas_
parents:
358
diff
changeset
|
76 { |
96fb24f948b7
Merge collection_load_only_geometry() into collection_load().
zas_
parents:
358
diff
changeset
|
77 collection_load_stop(cd); |
9 | 78 |
359
96fb24f948b7
Merge collection_load_only_geometry() into collection_load().
zas_
parents:
358
diff
changeset
|
79 if (flush) |
96fb24f948b7
Merge collection_load_only_geometry() into collection_load().
zas_
parents:
358
diff
changeset
|
80 collect_manager_flush(); |
96fb24f948b7
Merge collection_load_only_geometry() into collection_load().
zas_
parents:
358
diff
changeset
|
81 else |
96fb24f948b7
Merge collection_load_only_geometry() into collection_load().
zas_
parents:
358
diff
changeset
|
82 entry = collect_manager_get_entry(path); |
9 | 83 |
359
96fb24f948b7
Merge collection_load_only_geometry() into collection_load().
zas_
parents:
358
diff
changeset
|
84 if (!append) |
96fb24f948b7
Merge collection_load_only_geometry() into collection_load().
zas_
parents:
358
diff
changeset
|
85 { |
96fb24f948b7
Merge collection_load_only_geometry() into collection_load().
zas_
parents:
358
diff
changeset
|
86 collection_list_free(cd->list); |
96fb24f948b7
Merge collection_load_only_geometry() into collection_load().
zas_
parents:
358
diff
changeset
|
87 cd->list = NULL; |
96fb24f948b7
Merge collection_load_only_geometry() into collection_load().
zas_
parents:
358
diff
changeset
|
88 } |
9 | 89 } |
90 | |
91 if (!path && !cd->path) return FALSE; | |
92 | |
93 if (!path) path = cd->path; | |
442 | 94 |
360
822040a51249
Increase collection_load() buffer size and do not activate
zas_
parents:
359
diff
changeset
|
95 if (debug) printf("collection load: append=%d flush=%d only_geometry=%d path=%s\n", |
822040a51249
Increase collection_load() buffer size and do not activate
zas_
parents:
359
diff
changeset
|
96 append, flush, only_geometry, path); |
9 | 97 |
98 /* load it */ | |
99 pathl = path_from_utf8(path); | |
100 f = fopen(pathl, "r"); | |
101 g_free(pathl); | |
102 if (!f) | |
103 { | |
104 printf("Failed to open collection file: \"%s\"\n", path); | |
105 return FALSE; | |
106 } | |
107 | |
108 while (fgets(s_buf, sizeof(s_buf), f)) | |
109 { | |
110 gchar *buf; | |
363
5b8617c3821c
collection_load(): accept whitespaces at start of lines.
zas_
parents:
362
diff
changeset
|
111 gchar *p = s_buf; |
5b8617c3821c
collection_load(): accept whitespaces at start of lines.
zas_
parents:
362
diff
changeset
|
112 |
5b8617c3821c
collection_load(): accept whitespaces at start of lines.
zas_
parents:
362
diff
changeset
|
113 /* Skip whitespaces and empty lines */ |
5b8617c3821c
collection_load(): accept whitespaces at start of lines.
zas_
parents:
362
diff
changeset
|
114 while (*p && g_ascii_isspace(*p)) p++; |
5b8617c3821c
collection_load(): accept whitespaces at start of lines.
zas_
parents:
362
diff
changeset
|
115 if (*p == '\n' || *p == '\r') continue; |
5b8617c3821c
collection_load(): accept whitespaces at start of lines.
zas_
parents:
362
diff
changeset
|
116 |
5b8617c3821c
collection_load(): accept whitespaces at start of lines.
zas_
parents:
362
diff
changeset
|
117 /* Parse comments */ |
5b8617c3821c
collection_load(): accept whitespaces at start of lines.
zas_
parents:
362
diff
changeset
|
118 if (*p == '#') |
9 | 119 { |
365 | 120 if (!need_header) continue; |
363
5b8617c3821c
collection_load(): accept whitespaces at start of lines.
zas_
parents:
362
diff
changeset
|
121 if (strncasecmp(p, GQ_COLLECTION_MARKER, strlen(GQ_COLLECTION_MARKER)) == 0) |
9 | 122 { |
123 /* Looks like an official collection, allow unchecked input. | |
124 * All this does is allow adding files that may not exist, | |
125 * which is needed for the collection manager to work. | |
126 * Also unofficial files abort after too many invalid entries. | |
127 */ | |
365 | 128 has_official_header = TRUE; |
361
e0295af4f716
collection_load(): replace official by limit_failures (and
zas_
parents:
360
diff
changeset
|
129 limit_failures = FALSE; |
9 | 130 } |
363
5b8617c3821c
collection_load(): accept whitespaces at start of lines.
zas_
parents:
362
diff
changeset
|
131 else if (strncmp(p, "#geometry:", 10 ) == 0 && |
442 | 132 scan_geometry(p + 10, &cd->window_x, &cd->window_y, &cd->window_w, &cd->window_h)) |
9 | 133 { |
365 | 134 has_geometry_header = TRUE; |
9 | 135 cd->window_read = TRUE; |
365 | 136 if (only_geometry) break; |
9 | 137 } |
364
4862e9a61f3d
collection_load(): fix typo (missing #) made in rev 453.
zas_
parents:
363
diff
changeset
|
138 else if (strncasecmp(p, "#GQview collection", strlen("#GQview collection")) == 0) |
360
822040a51249
Increase collection_load() buffer size and do not activate
zas_
parents:
359
diff
changeset
|
139 { |
822040a51249
Increase collection_load() buffer size and do not activate
zas_
parents:
359
diff
changeset
|
140 /* As 2008/04/15 there is no difference between our collection file format |
822040a51249
Increase collection_load() buffer size and do not activate
zas_
parents:
359
diff
changeset
|
141 * and GQview 2.1.5 collection file format so ignore failures as well. */ |
365 | 142 has_gqview_header = TRUE; |
361
e0295af4f716
collection_load(): replace official by limit_failures (and
zas_
parents:
360
diff
changeset
|
143 limit_failures = FALSE; |
360
822040a51249
Increase collection_load() buffer size and do not activate
zas_
parents:
359
diff
changeset
|
144 } |
365 | 145 need_header = (!has_official_header && !has_gqview_header) || !has_geometry_header; |
9 | 146 continue; |
147 } | |
148 | |
363
5b8617c3821c
collection_load(): accept whitespaces at start of lines.
zas_
parents:
362
diff
changeset
|
149 /* Read filenames */ |
5b8617c3821c
collection_load(): accept whitespaces at start of lines.
zas_
parents:
362
diff
changeset
|
150 buf = quoted_value(p, NULL); |
9 | 151 if (buf) |
152 { | |
153 gint valid; | |
442 | 154 |
138 | 155 if (!flush) |
156 changed |= collect_manager_process_action(entry, &buf); | |
442 | 157 |
138 | 158 valid = (buf[0] == '/' && collection_add_check(cd, file_data_new_simple(buf), FALSE, TRUE)); |
362 | 159 if (debug && !valid) printf("collection invalid file: %s\n", buf); |
9 | 160 g_free(buf); |
161 | |
162 total++; | |
366
ce00494827e2
collection_load(): use booleans and always count failures (for debug).
zas_
parents:
365
diff
changeset
|
163 if (!valid) |
9 | 164 { |
165 fail++; | |
366
ce00494827e2
collection_load(): use booleans and always count failures (for debug).
zas_
parents:
365
diff
changeset
|
166 if (limit_failures && |
ce00494827e2
collection_load(): use booleans and always count failures (for debug).
zas_
parents:
365
diff
changeset
|
167 fail > GQ_COLLECTION_FAIL_MIN && |
283 | 168 fail * 100 / total > GQ_COLLECTION_FAIL_PERCENT) |
9 | 169 { |
447 | 170 printf("%d invalid filenames in unofficial collection file, closing: %s\n", fail, path); |
9 | 171 success = FALSE; |
172 break; | |
173 } | |
174 } | |
175 } | |
176 } | |
177 | |
365 | 178 if (debug) printf("collection files: total = %d fail = %d official=%d gqview=%d geometry=%d\n", |
442 | 179 total, fail, has_official_header, has_gqview_header, has_geometry_header); |
362 | 180 |
9 | 181 fclose(f); |
365 | 182 if (only_geometry) return has_geometry_header; |
359
96fb24f948b7
Merge collection_load_only_geometry() into collection_load().
zas_
parents:
358
diff
changeset
|
183 |
138 | 184 if (!flush) |
185 { | |
186 gchar *buf = NULL; | |
187 while (collect_manager_process_action(entry, &buf)) | |
188 { | |
189 collection_add_check(cd, file_data_new_simple(buf), FALSE, TRUE); | |
190 changed = TRUE; | |
191 g_free(buf); | |
192 } | |
193 } | |
9 | 194 |
195 cd->list = collection_list_sort(cd->list, cd->sort_method); | |
442 | 196 |
138 | 197 if (!flush && changed && success) |
198 collection_save_private(cd, path); | |
442 | 199 |
138 | 200 if (!flush) |
201 collect_manager_entry_reset(entry); | |
442 | 202 |
9 | 203 if (!append) cd->changed = FALSE; |
204 | |
205 return success; | |
206 } | |
207 | |
358 | 208 gint collection_load(CollectionData *cd, const gchar *path, CollectionLoadFlags flags) |
9 | 209 { |
358 | 210 if (collection_load_private(cd, path, flags | COLLECTION_LOAD_FLUSH)) |
9 | 211 { |
212 layout_recent_add_path(cd->path); | |
213 return TRUE; | |
214 } | |
215 | |
216 return FALSE; | |
217 } | |
218 | |
219 static void collection_load_thumb_do(CollectionData *cd) | |
220 { | |
221 GdkPixbuf *pixbuf; | |
222 | |
223 if (!cd->thumb_loader || !g_list_find(cd->list, cd->thumb_info)) return; | |
224 | |
225 pixbuf = thumb_loader_get_pixbuf(cd->thumb_loader, TRUE); | |
226 collection_info_set_thumb(cd->thumb_info, pixbuf); | |
227 g_object_unref(pixbuf); | |
228 | |
229 if (cd->info_updated_func) cd->info_updated_func(cd, cd->thumb_info, cd->info_updated_data); | |
230 } | |
231 | |
232 static void collection_load_thumb_error_cb(ThumbLoader *tl, gpointer data) | |
233 { | |
234 CollectionData *cd = data; | |
235 | |
236 collection_load_thumb_do(cd); | |
237 collection_load_thumb_step(cd); | |
238 } | |
239 | |
240 static void collection_load_thumb_done_cb(ThumbLoader *tl, gpointer data) | |
241 { | |
242 CollectionData *cd = data; | |
243 | |
244 collection_load_thumb_do(cd); | |
245 collection_load_thumb_step(cd); | |
246 } | |
247 | |
248 static void collection_load_thumb_step(CollectionData *cd) | |
249 { | |
250 GList *work; | |
251 CollectInfo *ci; | |
252 | |
253 if (!cd->list) | |
254 { | |
255 collection_load_stop(cd); | |
256 return; | |
257 } | |
258 | |
259 work = cd->list; | |
260 ci = work->data; | |
261 work = work->next; | |
262 /* find first unloaded thumb */ | |
263 while (work && ci->pixbuf) | |
264 { | |
265 ci = work->data; | |
266 work = work->next; | |
267 } | |
268 | |
269 if (!ci || ci->pixbuf) | |
270 { | |
271 /* done */ | |
272 collection_load_stop(cd); | |
273 | |
274 /* send a NULL CollectInfo to notify end */ | |
275 if (cd->info_updated_func) cd->info_updated_func(cd, NULL, cd->info_updated_data); | |
276 | |
277 return; | |
278 } | |
279 | |
280 /* setup loader and call it */ | |
281 cd->thumb_info = ci; | |
282 thumb_loader_free(cd->thumb_loader); | |
333 | 283 cd->thumb_loader = thumb_loader_new(options->thumbnails.max_width, options->thumbnails.max_height); |
9 | 284 thumb_loader_set_callbacks(cd->thumb_loader, |
285 collection_load_thumb_done_cb, | |
286 collection_load_thumb_error_cb, | |
287 NULL, | |
288 cd); | |
289 | |
290 /* start it */ | |
138 | 291 if (!thumb_loader_start(cd->thumb_loader, ci->fd->path)) |
9 | 292 { |
293 /* error, handle it, do next */ | |
138 | 294 if (debug) printf("error loading thumb for %s\n", ci->fd->path); |
9 | 295 collection_load_thumb_do(cd); |
296 collection_load_thumb_step(cd); | |
297 } | |
298 } | |
299 | |
300 void collection_load_thumb_idle(CollectionData *cd) | |
301 { | |
302 if (!cd->thumb_loader) collection_load_thumb_step(cd); | |
303 } | |
304 | |
358 | 305 gint collection_load_begin(CollectionData *cd, const gchar *path, CollectionLoadFlags flags) |
9 | 306 { |
358 | 307 if (!collection_load(cd, path, flags)) return FALSE; |
9 | 308 |
309 collection_load_thumb_idle(cd); | |
310 | |
311 return TRUE; | |
312 } | |
313 | |
314 void collection_load_stop(CollectionData *cd) | |
315 { | |
316 if (!cd->thumb_loader) return; | |
317 | |
318 thumb_loader_free(cd->thumb_loader); | |
319 cd->thumb_loader = NULL; | |
320 } | |
321 | |
322 static gint collection_save_private(CollectionData *cd, const gchar *path) | |
323 { | |
312 | 324 SecureSaveInfo *ssi; |
9 | 325 GList *work; |
326 gchar *pathl; | |
327 | |
328 if (!path && !cd->path) return FALSE; | |
329 | |
330 if (!path) | |
331 { | |
332 path = cd->path; | |
333 } | |
334 | |
335 | |
312 | 336 pathl = path_from_utf8(path); |
337 ssi = secure_open(pathl); | |
9 | 338 g_free(pathl); |
312 | 339 if (!ssi) |
340 { | |
403 | 341 printf_term(_("failed to open collection (write) \"%s\"\n"), path); |
9 | 342 return FALSE; |
343 } | |
344 | |
312 | 345 secure_fprintf(ssi, "%s collection\n", GQ_COLLECTION_MARKER); |
346 secure_fprintf(ssi, "#created with %s version %s\n", GQ_APPNAME, VERSION); | |
9 | 347 |
348 collection_update_geometry(cd); | |
349 if (cd->window_read) | |
350 { | |
312 | 351 secure_fprintf(ssi, "#geometry: %d %d %d %d\n", cd->window_x, cd->window_y, cd->window_w, cd->window_h); |
9 | 352 } |
353 | |
354 work = cd->list; | |
312 | 355 while (work && secsave_errno == SS_ERR_NONE) |
9 | 356 { |
357 CollectInfo *ci = work->data; | |
312 | 358 secure_fprintf(ssi, "\"%s\"\n", ci->fd->path); |
9 | 359 work = work->next; |
360 } | |
361 | |
312 | 362 secure_fprintf(ssi, "#end\n"); |
9 | 363 |
312 | 364 if (secure_close(ssi)) |
9 | 365 { |
403 | 366 printf_term(_("error saving collection file: %s\nerror: %s\n"), path, |
367 secsave_strerror(secsave_errno)); | |
9 | 368 return FALSE; |
369 } | |
370 | |
371 if (!cd->path || strcmp(path, cd->path) != 0) | |
372 { | |
373 gchar *buf = cd->path; | |
374 cd->path = g_strdup(path); | |
375 path = cd->path; | |
376 g_free(buf); | |
377 | |
378 g_free(cd->name); | |
379 cd->name = g_strdup(filename_from_path(cd->path)); | |
380 | |
381 collection_path_changed(cd); | |
382 } | |
383 | |
384 cd->changed = FALSE; | |
385 | |
386 return TRUE; | |
387 } | |
388 | |
389 gint collection_save(CollectionData *cd, const gchar *path) | |
390 { | |
391 if (collection_save_private(cd, path)) | |
392 { | |
393 layout_recent_add_path(cd->path); | |
394 return TRUE; | |
395 } | |
396 | |
397 return FALSE; | |
398 } | |
399 | |
400 gint collection_load_only_geometry(CollectionData *cd, const gchar *path) | |
401 { | |
359
96fb24f948b7
Merge collection_load_only_geometry() into collection_load().
zas_
parents:
358
diff
changeset
|
402 return collection_load(cd, path, COLLECTION_LOAD_GEOMETRY); |
9 | 403 } |
404 | |
405 | |
406 /* | |
407 *------------------------------------------------------------------- | |
408 * collection manager | |
409 *------------------------------------------------------------------- | |
410 */ | |
411 | |
412 #define COLLECT_MANAGER_ACTIONS_PER_IDLE 1000 | |
413 #define COLLECT_MANAGER_FLUSH_DELAY 10000 | |
414 | |
415 struct _CollectManagerEntry | |
416 { | |
417 gchar *path; | |
138 | 418 GList *add_list; |
419 GHashTable *oldpath_hash; | |
420 GHashTable *newpath_hash; | |
421 gboolean empty; | |
9 | 422 }; |
423 | |
424 typedef enum { | |
425 COLLECTION_MANAGER_UPDATE, | |
426 COLLECTION_MANAGER_ADD, | |
427 COLLECTION_MANAGER_REMOVE | |
428 } CollectManagerType; | |
429 | |
430 typedef struct _CollectManagerAction CollectManagerAction; | |
431 struct _CollectManagerAction | |
432 { | |
433 gchar *oldpath; | |
434 gchar *newpath; | |
435 | |
436 CollectManagerType type; | |
437 | |
438 gint ref; | |
439 }; | |
440 | |
441 | |
442 static GList *collection_manager_entry_list = NULL; | |
443 static GList *collection_manager_action_list = NULL; | |
444 static GList *collection_manager_action_tail = NULL; | |
445 static gint collection_manager_timer_id = -1; | |
446 | |
447 | |
448 static CollectManagerAction *collect_manager_action_new(const gchar *oldpath, const gchar *newpath, | |
449 CollectManagerType type) | |
450 { | |
451 CollectManagerAction *action; | |
452 | |
453 action = g_new0(CollectManagerAction, 1); | |
454 action->ref = 1; | |
455 | |
456 action->oldpath = g_strdup(oldpath); | |
457 action->newpath = g_strdup(newpath); | |
458 | |
459 action->type = type; | |
460 | |
461 return action; | |
462 } | |
463 | |
464 static void collect_manager_action_ref(CollectManagerAction *action) | |
465 { | |
466 action->ref++; | |
467 } | |
468 | |
469 static void collect_manager_action_unref(CollectManagerAction *action) | |
470 { | |
471 action->ref--; | |
472 | |
473 if (action->ref > 0) return; | |
474 | |
475 g_free(action->oldpath); | |
476 g_free(action->newpath); | |
477 g_free(action); | |
478 } | |
479 | |
138 | 480 static void collect_manager_entry_free_data(CollectManagerEntry *entry) |
9 | 481 { |
482 GList *work; | |
483 | |
138 | 484 work = entry->add_list; |
9 | 485 while (work) |
486 { | |
487 CollectManagerAction *action; | |
488 | |
489 action = work->data; | |
490 work = work->next; | |
491 | |
492 collect_manager_action_unref(action); | |
493 } | |
138 | 494 g_list_free(entry->add_list); |
495 g_hash_table_destroy(entry->oldpath_hash); | |
496 g_hash_table_destroy(entry->newpath_hash); | |
497 } | |
498 | |
499 static void collect_manager_entry_init_data(CollectManagerEntry *entry) | |
500 { | |
501 entry->add_list = NULL; | |
502 entry->oldpath_hash = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, (GDestroyNotify) collect_manager_action_unref); | |
503 entry->newpath_hash = g_hash_table_new(g_str_hash, g_str_equal); | |
504 entry->empty = TRUE; | |
505 | |
506 } | |
507 | |
508 static CollectManagerEntry *collect_manager_entry_new(const gchar *path) | |
509 { | |
510 CollectManagerEntry *entry; | |
511 | |
512 entry = g_new0(CollectManagerEntry, 1); | |
513 entry->path = g_strdup(path); | |
514 collect_manager_entry_init_data(entry); | |
515 | |
516 collection_manager_entry_list = g_list_append(collection_manager_entry_list, entry); | |
517 | |
518 return entry; | |
519 } | |
520 | |
521 | |
522 static void collect_manager_entry_free(CollectManagerEntry *entry) | |
523 { | |
524 collection_manager_entry_list = g_list_remove(collection_manager_entry_list, entry); | |
525 | |
526 collect_manager_entry_free_data(entry); | |
9 | 527 |
528 g_free(entry->path); | |
529 g_free(entry); | |
530 } | |
531 | |
138 | 532 static void collect_manager_entry_reset(CollectManagerEntry *entry) |
533 { | |
534 collect_manager_entry_free_data(entry); | |
535 collect_manager_entry_init_data(entry); | |
536 } | |
537 | |
538 static CollectManagerEntry *collect_manager_get_entry(const gchar *path) | |
539 { | |
540 GList *work; | |
541 | |
542 work = collection_manager_entry_list; | |
543 while (work) | |
544 { | |
545 CollectManagerEntry *entry; | |
546 | |
547 entry = work->data; | |
548 work = work->next; | |
442 | 549 if (strcmp(entry->path, path) == 0) |
138 | 550 { |
551 return entry; | |
552 } | |
553 } | |
554 return NULL; | |
555 | |
556 } | |
557 | |
558 static void collect_manager_entry_add_action(CollectManagerEntry *entry, CollectManagerAction *action) | |
559 { | |
560 | |
561 CollectManagerAction *orig_action; | |
442 | 562 |
563 entry->empty = FALSE; | |
564 | |
138 | 565 if (action->oldpath == NULL) |
566 { | |
567 /* add file */ | |
568 if (action->newpath == NULL) | |
569 { | |
570 return; | |
571 } | |
442 | 572 |
138 | 573 orig_action = g_hash_table_lookup(entry->newpath_hash, action->newpath); |
574 if (orig_action) | |
575 { | |
576 /* target already exists */ | |
577 printf("collection manager failed to add another action for target %s in collection %s\n", | |
578 action->newpath, entry->path); | |
579 return; | |
580 } | |
581 entry->add_list = g_list_append(entry->add_list, action); | |
582 g_hash_table_insert(entry->newpath_hash, action->newpath, action); | |
583 collect_manager_action_ref(action); | |
584 return; | |
585 } | |
586 | |
587 orig_action = g_hash_table_lookup(entry->newpath_hash, action->oldpath); | |
588 if (orig_action) | |
589 { | |
590 /* new action with the same file */ | |
591 CollectManagerAction *new_action = collect_manager_action_new(orig_action->oldpath, action->newpath, action->type); | |
442 | 592 |
138 | 593 if (new_action->oldpath) |
594 { | |
595 g_hash_table_steal(entry->oldpath_hash, orig_action->oldpath); | |
596 g_hash_table_insert(entry->oldpath_hash, new_action->oldpath, new_action); | |
597 } | |
598 else | |
599 { | |
600 GList *work = g_list_find(entry->add_list, orig_action); | |
601 work->data = new_action; | |
602 } | |
442 | 603 |
138 | 604 g_hash_table_steal(entry->newpath_hash, orig_action->newpath); |
442 | 605 if (new_action->newpath) |
138 | 606 { |
442 | 607 g_hash_table_insert(entry->newpath_hash, new_action->newpath, new_action); |
138 | 608 } |
609 collect_manager_action_unref(orig_action); | |
610 return; | |
611 } | |
612 | |
613 | |
614 orig_action = g_hash_table_lookup(entry->oldpath_hash, action->oldpath); | |
615 if (orig_action) | |
616 { | |
617 /* another action for the same source, ignore */ | |
618 printf("collection manager failed to add another action for source %s in collection %s\n", | |
619 action->oldpath, entry->path); | |
620 return; | |
621 } | |
442 | 622 |
138 | 623 g_hash_table_insert(entry->oldpath_hash, action->oldpath, action); |
624 if (action->newpath) | |
625 { | |
442 | 626 g_hash_table_insert(entry->newpath_hash, action->newpath, action); |
138 | 627 } |
628 collect_manager_action_ref(action); | |
629 } | |
630 | |
235 | 631 static gint collect_manager_process_action(CollectManagerEntry *entry, gchar **path_ptr) |
138 | 632 { |
633 gchar *path = *path_ptr; | |
634 CollectManagerAction *action; | |
442 | 635 |
138 | 636 if (path == NULL) |
637 { | |
638 /* get new files */ | |
639 if (entry->add_list) | |
640 { | |
641 action = entry->add_list->data; | |
642 g_assert(action->oldpath == NULL); | |
643 entry->add_list = g_list_remove(entry->add_list, action); | |
644 path = g_strdup(action->newpath); | |
645 g_hash_table_remove(entry->newpath_hash, path); | |
646 collect_manager_action_unref(action); | |
647 } | |
648 *path_ptr = path; | |
649 return (path != NULL); | |
650 } | |
442 | 651 |
138 | 652 action = g_hash_table_lookup(entry->oldpath_hash, path); |
442 | 653 |
138 | 654 if (action) |
655 { | |
656 g_free(path); | |
657 path = g_strdup(action->newpath); | |
658 *path_ptr = path; | |
659 return TRUE; | |
660 } | |
661 | |
662 return FALSE; /* no change */ | |
663 } | |
664 | |
9 | 665 static void collect_manager_refresh(void) |
666 { | |
667 GList *list = NULL; | |
668 GList *work; | |
669 gchar *base; | |
670 | |
283 | 671 base = g_strconcat(homedir(), "/", GQ_RC_DIR_COLLECTIONS, NULL); |
9 | 672 path_list(base, &list, NULL); |
673 g_free(base); | |
674 | |
675 work = collection_manager_entry_list; | |
676 while (work && list) | |
677 { | |
678 CollectManagerEntry *entry; | |
679 GList *list_step; | |
680 | |
681 entry = work->data; | |
682 work = work->next; | |
683 | |
684 list_step = list; | |
685 while (list_step && entry) | |
686 { | |
687 gchar *path; | |
688 | |
689 path = list_step->data; | |
690 list_step = list_step->next; | |
691 | |
692 if (strcmp(path, entry->path) == 0) | |
693 { | |
694 list = g_list_remove(list, path); | |
695 g_free(path); | |
696 | |
697 entry = NULL; | |
698 } | |
699 else | |
700 { | |
701 collect_manager_entry_free(entry); | |
702 } | |
703 } | |
704 } | |
705 | |
706 work = list; | |
707 while (work) | |
708 { | |
709 gchar *path; | |
710 | |
711 path = work->data; | |
712 work = work->next; | |
713 | |
714 collect_manager_entry_new(path); | |
715 g_free(path); | |
716 } | |
717 | |
718 g_list_free(list); | |
719 } | |
720 | |
721 static void collect_manager_process_actions(gint max) | |
722 { | |
723 if (debug && collection_manager_action_list) | |
724 { | |
725 printf("collection manager processing actions\n"); | |
726 } | |
727 | |
728 while (collection_manager_action_list != NULL && max > 0) | |
729 { | |
730 CollectManagerAction *action; | |
731 GList *work; | |
732 | |
733 action = collection_manager_action_list->data; | |
734 work = collection_manager_entry_list; | |
735 while (work) | |
736 { | |
737 CollectManagerEntry *entry; | |
738 | |
739 entry = work->data; | |
740 work = work->next; | |
741 | |
742 if (action->type == COLLECTION_MANAGER_UPDATE) | |
743 { | |
138 | 744 collect_manager_entry_add_action(entry, action); |
9 | 745 } |
746 else if (action->oldpath && action->newpath && | |
747 strcmp(action->newpath, entry->path) == 0) | |
748 { | |
749 /* convert action to standard add format */ | |
750 g_free(action->newpath); | |
751 if (action->type == COLLECTION_MANAGER_ADD) | |
752 { | |
753 action->newpath = action->oldpath; | |
754 action->oldpath = NULL; | |
755 } | |
756 else if (action->type == COLLECTION_MANAGER_REMOVE) | |
757 { | |
758 action->newpath = NULL; | |
759 } | |
138 | 760 collect_manager_entry_add_action(entry, action); |
9 | 761 } |
762 | |
763 max--; | |
764 } | |
765 | |
766 if (action->type != COLLECTION_MANAGER_UPDATE && | |
767 action->oldpath && action->newpath) | |
768 { | |
769 printf("collection manager failed to %s %s for collection %s\n", | |
770 (action->type == COLLECTION_MANAGER_ADD) ? "add" : "remove", | |
771 action->oldpath, action->newpath); | |
772 } | |
773 | |
774 if (collection_manager_action_tail == collection_manager_action_list) | |
775 { | |
776 collection_manager_action_tail = NULL; | |
777 } | |
778 collection_manager_action_list = g_list_remove(collection_manager_action_list, action); | |
779 collect_manager_action_unref(action); | |
780 } | |
781 } | |
782 | |
783 static gint collect_manager_process_entry(CollectManagerEntry *entry) | |
784 { | |
785 CollectionData *cd; | |
786 gint success; | |
787 | |
138 | 788 if (entry->empty) return FALSE; |
9 | 789 |
790 cd = collection_new(entry->path); | |
358 | 791 success = collection_load_private(cd, entry->path, COLLECTION_LOAD_NONE); |
9 | 792 |
793 collection_unref(cd); | |
794 | |
795 return TRUE; | |
796 } | |
797 | |
798 static gint collect_manager_process_entry_list(void) | |
799 { | |
800 GList *work; | |
801 | |
802 work = collection_manager_entry_list; | |
803 while (work) | |
804 { | |
805 CollectManagerEntry *entry; | |
806 | |
807 entry = work->data; | |
808 work = work->next; | |
809 if (collect_manager_process_entry(entry)) return TRUE; | |
810 } | |
811 | |
812 return FALSE; | |
813 } | |
814 | |
138 | 815 |
816 | |
9 | 817 static gint collect_manager_process_cb(gpointer data) |
818 { | |
819 if (collection_manager_action_list) collect_manager_refresh(); | |
820 collect_manager_process_actions(COLLECT_MANAGER_ACTIONS_PER_IDLE); | |
821 if (collection_manager_action_list) return TRUE; | |
822 | |
823 if (collect_manager_process_entry_list()) return TRUE; | |
824 | |
825 if (debug) printf("collection manager is up to date\n"); | |
826 return FALSE; | |
827 } | |
828 | |
829 static gint collect_manager_timer_cb(gpointer data) | |
830 { | |
831 if (debug) printf("collection manager timer expired\n"); | |
832 | |
833 g_idle_add_full(G_PRIORITY_LOW, collect_manager_process_cb, NULL, NULL); | |
834 | |
835 collection_manager_timer_id = -1; | |
836 return FALSE; | |
837 } | |
838 | |
839 static void collect_manager_timer_push(gint stop) | |
840 { | |
841 if (collection_manager_timer_id != -1) | |
842 { | |
843 if (!stop) return; | |
844 | |
845 g_source_remove(collection_manager_timer_id); | |
846 collection_manager_timer_id = -1; | |
847 } | |
848 | |
849 if (!stop) | |
850 { | |
851 collection_manager_timer_id = g_timeout_add(COLLECT_MANAGER_FLUSH_DELAY, | |
852 collect_manager_timer_cb, NULL); | |
853 if (debug) printf("collection manager timer started\n"); | |
854 } | |
855 } | |
856 | |
857 static void collect_manager_add_action(CollectManagerAction *action) | |
858 { | |
859 if (!action) return; | |
860 | |
861 /* we keep track of the list's tail to keep this a n(1) operation */ | |
862 | |
863 if (collection_manager_action_tail) | |
864 { | |
66
ebbff299ad0d
Fri Sep 1 02:12:45 2006 John Ellis <johne@verizon.net>
gqview
parents:
9
diff
changeset
|
865 collection_manager_action_tail = g_list_append(collection_manager_action_tail, action); |
9 | 866 collection_manager_action_tail = collection_manager_action_tail->next; |
867 } | |
868 else | |
869 { | |
870 collection_manager_action_list = g_list_append(collection_manager_action_list, action); | |
871 collection_manager_action_tail = collection_manager_action_list; | |
872 } | |
873 | |
874 collect_manager_timer_push(FALSE); | |
875 } | |
876 | |
138 | 877 void collect_manager_moved(FileData *fd) |
9 | 878 { |
879 CollectManagerAction *action; | |
138 | 880 const gchar *oldpath = fd->change->source; |
881 const gchar *newpath = fd->change->dest; | |
9 | 882 |
883 action = collect_manager_action_new(oldpath, newpath, COLLECTION_MANAGER_UPDATE); | |
884 collect_manager_add_action(action); | |
885 } | |
886 | |
138 | 887 void collect_manager_add(FileData *fd, const gchar *collection) |
9 | 888 { |
889 CollectManagerAction *action; | |
890 CollectWindow *cw; | |
891 | |
138 | 892 if (!fd || !collection) return; |
9 | 893 |
894 cw = collection_window_find_by_path(collection); | |
895 if (cw) | |
896 { | |
138 | 897 if (collection_list_find(cw->cd->list, fd->path) == NULL) |
9 | 898 { |
138 | 899 collection_add(cw->cd, fd, FALSE); |
9 | 900 } |
901 return; | |
902 } | |
903 | |
138 | 904 action = collect_manager_action_new(fd->path, collection, COLLECTION_MANAGER_ADD); |
9 | 905 collect_manager_add_action(action); |
906 } | |
907 | |
138 | 908 void collect_manager_remove(FileData *fd, const gchar *collection) |
9 | 909 { |
910 CollectManagerAction *action; | |
911 CollectWindow *cw; | |
912 | |
138 | 913 if (!fd || !collection) return; |
9 | 914 |
915 cw = collection_window_find_by_path(collection); | |
916 if (cw) | |
917 { | |
138 | 918 while (collection_remove(cw->cd, fd)); |
9 | 919 return; |
920 } | |
921 | |
138 | 922 action = collect_manager_action_new(fd->path, collection, COLLECTION_MANAGER_REMOVE); |
9 | 923 collect_manager_add_action(action); |
924 } | |
925 | |
926 void collect_manager_flush(void) | |
927 { | |
928 collect_manager_timer_push(TRUE); | |
929 | |
930 if (debug) printf("collection manager flushing\n"); | |
931 while (collect_manager_process_cb(NULL)); | |
932 } |