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