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