9
|
1 /*
|
|
2 * GQview
|
|
3 * (C) 2004 John Ellis
|
|
4 *
|
|
5 * Author: John Ellis
|
|
6 *
|
|
7 * This software is released under the GNU General Public License (GNU GPL).
|
|
8 * Please read the included file COPYING for more information.
|
|
9 * This software comes with no warranty of any kind, use at your own risk!
|
|
10 */
|
|
11
|
|
12
|
|
13 #include "gqview.h"
|
|
14 #include "collect-io.h"
|
|
15
|
|
16 #include "collect.h"
|
|
17 #include "layout_util.h"
|
|
18 #include "rcfile.h"
|
|
19 #include "thumb.h"
|
|
20 #include "ui_fileops.h"
|
|
21
|
|
22
|
|
23 #define GQVIEW_COLLECTION_MARKER "#GQview"
|
|
24
|
|
25 #define GQVIEW_COLLECTION_FAIL_MIN 300
|
|
26 #define GQVIEW_COLLECTION_FAIL_PERCENT 98
|
|
27
|
|
28
|
|
29 static void collection_load_thumb_step(CollectionData *cd);
|
|
30
|
|
31
|
|
32 static gint scan_geometry(gchar *buffer, gint *x, gint *y, gint *w, gint *h)
|
|
33 {
|
|
34 gint nx, ny, nw, nh;
|
|
35
|
|
36 if(sscanf(buffer, "%d %d %d %d", &nx, &ny, &nw, &nh) != 4) return FALSE;
|
|
37
|
|
38 *x = nx;
|
|
39 *y = ny;
|
|
40 *w = nw;
|
|
41 *h = nh;
|
|
42
|
|
43 return TRUE;
|
|
44 }
|
|
45
|
|
46 static gint collection_load_private(CollectionData *cd, const gchar *path, gint append, gint flush)
|
|
47 {
|
|
48 gchar s_buf[2048];
|
|
49 FILE *f;
|
|
50 gchar *pathl;
|
|
51 gint official = FALSE;
|
|
52 gint success = TRUE;
|
|
53 guint total = 0;
|
|
54 guint fail = 0;
|
|
55
|
|
56 collection_load_stop(cd);
|
|
57
|
|
58 if (flush) collect_manager_flush();
|
|
59
|
|
60 if (!append)
|
|
61 {
|
|
62 collection_list_free(cd->list);
|
|
63 cd->list = NULL;
|
|
64 }
|
|
65
|
|
66 if (!path && !cd->path) return FALSE;
|
|
67
|
|
68 if (!path) path = cd->path;
|
|
69
|
|
70 /* load it */
|
|
71 pathl = path_from_utf8(path);
|
|
72 f = fopen(pathl, "r");
|
|
73 g_free(pathl);
|
|
74 if (!f)
|
|
75 {
|
|
76 printf("Failed to open collection file: \"%s\"\n", path);
|
|
77 return FALSE;
|
|
78 }
|
|
79
|
|
80 while (fgets(s_buf, sizeof(s_buf), f))
|
|
81 {
|
|
82 gchar *buf;
|
|
83 if (s_buf[0]=='#')
|
|
84 {
|
|
85 if (strncasecmp(s_buf, GQVIEW_COLLECTION_MARKER, strlen(GQVIEW_COLLECTION_MARKER)) == 0)
|
|
86 {
|
|
87 /* Looks like an official collection, allow unchecked input.
|
|
88 * All this does is allow adding files that may not exist,
|
|
89 * which is needed for the collection manager to work.
|
|
90 * Also unofficial files abort after too many invalid entries.
|
|
91 */
|
|
92 official = TRUE;
|
|
93 }
|
|
94 else if (strncmp(s_buf, "#geometry:", 10 ) == 0 &&
|
|
95 scan_geometry(s_buf + 10, &cd->window_x, &cd->window_y, &cd->window_w, &cd->window_h) )
|
|
96 {
|
|
97 cd->window_read = TRUE;
|
|
98 }
|
|
99 continue;
|
|
100 }
|
|
101 if (s_buf[0]=='\n') continue;
|
|
102
|
|
103 buf = quoted_value(s_buf);
|
|
104 if (buf)
|
|
105 {
|
|
106 gint valid;
|
|
107
|
|
108 valid = (buf[0] == '/' && collection_add_check(cd, buf, FALSE, flush));
|
|
109 g_free(buf);
|
|
110
|
|
111 total++;
|
|
112 if (!valid && !official)
|
|
113 {
|
|
114 fail++;
|
|
115 if (fail > GQVIEW_COLLECTION_FAIL_MIN &&
|
|
116 fail * 100 / total > GQVIEW_COLLECTION_FAIL_PERCENT)
|
|
117 {
|
|
118 printf("Too many invalid filenames in unoffical collection file, closing: %s\n", path);
|
|
119 success = FALSE;
|
|
120 break;
|
|
121 }
|
|
122 }
|
|
123 }
|
|
124 }
|
|
125
|
|
126 fclose(f);
|
|
127
|
|
128 cd->list = collection_list_sort(cd->list, cd->sort_method);
|
|
129 if (!append) cd->changed = FALSE;
|
|
130
|
|
131 return success;
|
|
132 }
|
|
133
|
|
134 gint collection_load(CollectionData *cd, const gchar *path, gint append)
|
|
135 {
|
|
136 if (collection_load_private(cd, path, append, TRUE))
|
|
137 {
|
|
138 layout_recent_add_path(cd->path);
|
|
139 return TRUE;
|
|
140 }
|
|
141
|
|
142 return FALSE;
|
|
143 }
|
|
144
|
|
145 static void collection_load_thumb_do(CollectionData *cd)
|
|
146 {
|
|
147 GdkPixbuf *pixbuf;
|
|
148
|
|
149 if (!cd->thumb_loader || !g_list_find(cd->list, cd->thumb_info)) return;
|
|
150
|
|
151 pixbuf = thumb_loader_get_pixbuf(cd->thumb_loader, TRUE);
|
|
152 collection_info_set_thumb(cd->thumb_info, pixbuf);
|
|
153 g_object_unref(pixbuf);
|
|
154
|
|
155 if (cd->info_updated_func) cd->info_updated_func(cd, cd->thumb_info, cd->info_updated_data);
|
|
156 }
|
|
157
|
|
158 static void collection_load_thumb_error_cb(ThumbLoader *tl, gpointer data)
|
|
159 {
|
|
160 CollectionData *cd = data;
|
|
161
|
|
162 collection_load_thumb_do(cd);
|
|
163 collection_load_thumb_step(cd);
|
|
164 }
|
|
165
|
|
166 static void collection_load_thumb_done_cb(ThumbLoader *tl, gpointer data)
|
|
167 {
|
|
168 CollectionData *cd = data;
|
|
169
|
|
170 collection_load_thumb_do(cd);
|
|
171 collection_load_thumb_step(cd);
|
|
172 }
|
|
173
|
|
174 static void collection_load_thumb_step(CollectionData *cd)
|
|
175 {
|
|
176 GList *work;
|
|
177 CollectInfo *ci;
|
|
178
|
|
179 if (!cd->list)
|
|
180 {
|
|
181 collection_load_stop(cd);
|
|
182 return;
|
|
183 }
|
|
184
|
|
185 work = cd->list;
|
|
186 ci = work->data;
|
|
187 work = work->next;
|
|
188 /* find first unloaded thumb */
|
|
189 while (work && ci->pixbuf)
|
|
190 {
|
|
191 ci = work->data;
|
|
192 work = work->next;
|
|
193 }
|
|
194
|
|
195 if (!ci || ci->pixbuf)
|
|
196 {
|
|
197 /* done */
|
|
198 collection_load_stop(cd);
|
|
199
|
|
200 /* send a NULL CollectInfo to notify end */
|
|
201 if (cd->info_updated_func) cd->info_updated_func(cd, NULL, cd->info_updated_data);
|
|
202
|
|
203 return;
|
|
204 }
|
|
205
|
|
206 /* setup loader and call it */
|
|
207 cd->thumb_info = ci;
|
|
208 thumb_loader_free(cd->thumb_loader);
|
|
209 cd->thumb_loader = thumb_loader_new(thumb_max_width, thumb_max_height);
|
|
210 thumb_loader_set_callbacks(cd->thumb_loader,
|
|
211 collection_load_thumb_done_cb,
|
|
212 collection_load_thumb_error_cb,
|
|
213 NULL,
|
|
214 cd);
|
|
215
|
|
216 /* start it */
|
|
217 if (!thumb_loader_start(cd->thumb_loader, ci->path))
|
|
218 {
|
|
219 /* error, handle it, do next */
|
|
220 if (debug) printf("error loading thumb for %s\n", ci->path);
|
|
221 collection_load_thumb_do(cd);
|
|
222 collection_load_thumb_step(cd);
|
|
223 }
|
|
224 }
|
|
225
|
|
226 void collection_load_thumb_idle(CollectionData *cd)
|
|
227 {
|
|
228 if (!cd->thumb_loader) collection_load_thumb_step(cd);
|
|
229 }
|
|
230
|
|
231 gint collection_load_begin(CollectionData *cd, const gchar *path, gint append)
|
|
232 {
|
|
233 if (!collection_load(cd, path, append)) return FALSE;
|
|
234
|
|
235 collection_load_thumb_idle(cd);
|
|
236
|
|
237 return TRUE;
|
|
238 }
|
|
239
|
|
240 void collection_load_stop(CollectionData *cd)
|
|
241 {
|
|
242 if (!cd->thumb_loader) return;
|
|
243
|
|
244 thumb_loader_free(cd->thumb_loader);
|
|
245 cd->thumb_loader = NULL;
|
|
246 }
|
|
247
|
|
248 static gint collection_save_private(CollectionData *cd, const gchar *path)
|
|
249 {
|
|
250 FILE *f;
|
|
251 GList *work;
|
|
252 gchar *tmp_path;
|
|
253 gchar *pathl;
|
|
254 mode_t save_mask;
|
|
255
|
|
256 if (!path && !cd->path) return FALSE;
|
|
257
|
|
258 if (!path)
|
|
259 {
|
|
260 path = cd->path;
|
|
261 }
|
|
262
|
|
263 tmp_path = unique_filename(path, ".tmp", "_", 3);
|
|
264 if (!tmp_path) return FALSE;
|
|
265
|
|
266 pathl = path_from_utf8(tmp_path);
|
|
267 save_mask = umask(0077);
|
|
268 f = fopen(pathl, "w");
|
|
269 umask(save_mask);
|
|
270 g_free(pathl);
|
|
271
|
|
272 if (!f)
|
|
273 {
|
|
274 /* file open failed */
|
|
275 printf("failed to open collection (write) \"%s\"\n", tmp_path);
|
|
276 g_free(tmp_path);
|
|
277 return FALSE;
|
|
278 }
|
|
279
|
|
280 fprintf(f, "%s collection\n", GQVIEW_COLLECTION_MARKER);
|
|
281 fprintf(f, "#created with GQview version %s\n", VERSION);
|
|
282
|
|
283 collection_update_geometry(cd);
|
|
284 if (cd->window_read)
|
|
285 {
|
|
286 fprintf(f, "#geometry: %d %d %d %d\n", cd->window_x, cd->window_y, cd->window_w, cd->window_h);
|
|
287 }
|
|
288
|
|
289 work = cd->list;
|
|
290 while (work)
|
|
291 {
|
|
292 CollectInfo *ci = work->data;
|
|
293 if (fprintf(f, "\"%s\"\n", ci->path) < 0)
|
|
294 {
|
|
295 fclose(f);
|
|
296 printf("Error writing to %s\n", tmp_path);
|
|
297 unlink_file(tmp_path);
|
|
298 g_free(tmp_path);
|
|
299 return FALSE;
|
|
300 }
|
|
301 work = work->next;
|
|
302 }
|
|
303
|
|
304 fprintf(f, "#end\n");
|
|
305
|
|
306 fclose(f);
|
|
307
|
|
308 copy_file_attributes(path, tmp_path, TRUE, FALSE);
|
|
309 if (!rename_file(tmp_path, path))
|
|
310 {
|
|
311 printf("collection save unable to rename %s to %s\n", tmp_path, path);
|
|
312 unlink_file(tmp_path);
|
|
313 g_free(tmp_path);
|
|
314 return FALSE;
|
|
315 }
|
|
316
|
|
317 g_free(tmp_path);
|
|
318
|
|
319 if (!cd->path || strcmp(path, cd->path) != 0)
|
|
320 {
|
|
321 gchar *buf = cd->path;
|
|
322 cd->path = g_strdup(path);
|
|
323 path = cd->path;
|
|
324 g_free(buf);
|
|
325
|
|
326 g_free(cd->name);
|
|
327 cd->name = g_strdup(filename_from_path(cd->path));
|
|
328
|
|
329 collection_path_changed(cd);
|
|
330 }
|
|
331
|
|
332 cd->changed = FALSE;
|
|
333
|
|
334 return TRUE;
|
|
335 }
|
|
336
|
|
337 gint collection_save(CollectionData *cd, const gchar *path)
|
|
338 {
|
|
339 if (collection_save_private(cd, path))
|
|
340 {
|
|
341 layout_recent_add_path(cd->path);
|
|
342 return TRUE;
|
|
343 }
|
|
344
|
|
345 return FALSE;
|
|
346 }
|
|
347
|
|
348 gint collection_load_only_geometry(CollectionData *cd, const gchar *path)
|
|
349 {
|
|
350 gchar s_buf[2048];
|
|
351 FILE *f;
|
|
352 gchar *pathl;
|
|
353
|
|
354 if (!path && !cd->path) return FALSE;
|
|
355
|
|
356 if (!path) path = cd->path;
|
|
357
|
|
358 /* load it */
|
|
359 pathl = path_from_utf8(path);
|
|
360 f = fopen(pathl, "r");
|
|
361 g_free(pathl);
|
|
362 if (!f) return FALSE;
|
|
363
|
|
364 while (fgets(s_buf, sizeof(s_buf), f))
|
|
365 {
|
|
366 if (s_buf[0]=='#' &&
|
|
367 strncmp(s_buf, "#geometry:", 10 ) == 0 &&
|
|
368 scan_geometry(s_buf + 10, &cd->window_x, &cd->window_y, &cd->window_w, &cd->window_h) )
|
|
369 {
|
|
370 cd->window_read = TRUE;
|
|
371 fclose(f);
|
|
372 return TRUE;
|
|
373 }
|
|
374 }
|
|
375 fclose(f);
|
|
376 return FALSE;
|
|
377 }
|
|
378
|
|
379
|
|
380 /*
|
|
381 *-------------------------------------------------------------------
|
|
382 * collection manager
|
|
383 *-------------------------------------------------------------------
|
|
384 */
|
|
385
|
|
386 #define COLLECT_MANAGER_ACTIONS_PER_IDLE 1000
|
|
387 #define COLLECT_MANAGER_FLUSH_DELAY 10000
|
|
388
|
|
389 typedef struct _CollectManagerEntry CollectManagerEntry;
|
|
390 struct _CollectManagerEntry
|
|
391 {
|
|
392 gchar *path;
|
|
393 GList *action_list;
|
|
394 };
|
|
395
|
|
396 typedef enum {
|
|
397 COLLECTION_MANAGER_UPDATE,
|
|
398 COLLECTION_MANAGER_ADD,
|
|
399 COLLECTION_MANAGER_REMOVE
|
|
400 } CollectManagerType;
|
|
401
|
|
402 typedef struct _CollectManagerAction CollectManagerAction;
|
|
403 struct _CollectManagerAction
|
|
404 {
|
|
405 gchar *oldpath;
|
|
406 gchar *newpath;
|
|
407
|
|
408 CollectManagerType type;
|
|
409
|
|
410 gint ref;
|
|
411 };
|
|
412
|
|
413
|
|
414 static GList *collection_manager_entry_list = NULL;
|
|
415 static GList *collection_manager_action_list = NULL;
|
|
416 static GList *collection_manager_action_tail = NULL;
|
|
417 static gint collection_manager_timer_id = -1;
|
|
418
|
|
419
|
|
420 static CollectManagerAction *collect_manager_action_new(const gchar *oldpath, const gchar *newpath,
|
|
421 CollectManagerType type)
|
|
422 {
|
|
423 CollectManagerAction *action;
|
|
424
|
|
425 action = g_new0(CollectManagerAction, 1);
|
|
426 action->ref = 1;
|
|
427
|
|
428 action->oldpath = g_strdup(oldpath);
|
|
429 action->newpath = g_strdup(newpath);
|
|
430
|
|
431 action->type = type;
|
|
432
|
|
433 return action;
|
|
434 }
|
|
435
|
|
436 static void collect_manager_action_ref(CollectManagerAction *action)
|
|
437 {
|
|
438 action->ref++;
|
|
439 }
|
|
440
|
|
441 static void collect_manager_action_unref(CollectManagerAction *action)
|
|
442 {
|
|
443 action->ref--;
|
|
444
|
|
445 if (action->ref > 0) return;
|
|
446
|
|
447 g_free(action->oldpath);
|
|
448 g_free(action->newpath);
|
|
449 g_free(action);
|
|
450 }
|
|
451
|
|
452 static CollectManagerEntry *collect_manager_entry_new(const gchar *path)
|
|
453 {
|
|
454 CollectManagerEntry *entry;
|
|
455
|
|
456 entry = g_new0(CollectManagerEntry, 1);
|
|
457 entry->path = g_strdup(path);
|
|
458 entry->action_list = NULL;
|
|
459
|
|
460 collection_manager_entry_list = g_list_append(collection_manager_entry_list, entry);
|
|
461
|
|
462 return entry;
|
|
463 }
|
|
464
|
|
465 static void collect_manager_entry_free(CollectManagerEntry *entry)
|
|
466 {
|
|
467 GList *work;
|
|
468
|
|
469 collection_manager_entry_list = g_list_remove(collection_manager_entry_list, entry);
|
|
470
|
|
471 work = entry->action_list;
|
|
472 while (work)
|
|
473 {
|
|
474 CollectManagerAction *action;
|
|
475
|
|
476 action = work->data;
|
|
477 work = work->next;
|
|
478
|
|
479 collect_manager_action_unref(action);
|
|
480 }
|
|
481 g_list_free(entry->action_list);
|
|
482
|
|
483 g_free(entry->path);
|
|
484 g_free(entry);
|
|
485 }
|
|
486
|
|
487 static void collect_manager_refresh(void)
|
|
488 {
|
|
489 GList *list = NULL;
|
|
490 GList *work;
|
|
491 gchar *base;
|
|
492
|
|
493 base = g_strconcat(homedir(), "/", GQVIEW_RC_DIR_COLLECTIONS, NULL);
|
|
494 path_list(base, &list, NULL);
|
|
495 g_free(base);
|
|
496
|
|
497 work = collection_manager_entry_list;
|
|
498 while (work && list)
|
|
499 {
|
|
500 CollectManagerEntry *entry;
|
|
501 GList *list_step;
|
|
502
|
|
503 entry = work->data;
|
|
504 work = work->next;
|
|
505
|
|
506 list_step = list;
|
|
507 while (list_step && entry)
|
|
508 {
|
|
509 gchar *path;
|
|
510
|
|
511 path = list_step->data;
|
|
512 list_step = list_step->next;
|
|
513
|
|
514 if (strcmp(path, entry->path) == 0)
|
|
515 {
|
|
516 list = g_list_remove(list, path);
|
|
517 g_free(path);
|
|
518
|
|
519 entry = NULL;
|
|
520 }
|
|
521 else
|
|
522 {
|
|
523 collect_manager_entry_free(entry);
|
|
524 }
|
|
525 }
|
|
526 }
|
|
527
|
|
528 work = list;
|
|
529 while (work)
|
|
530 {
|
|
531 gchar *path;
|
|
532
|
|
533 path = work->data;
|
|
534 work = work->next;
|
|
535
|
|
536 collect_manager_entry_new(path);
|
|
537 g_free(path);
|
|
538 }
|
|
539
|
|
540 g_list_free(list);
|
|
541 }
|
|
542
|
|
543 static void collect_manager_process_actions(gint max)
|
|
544 {
|
|
545 if (debug && collection_manager_action_list)
|
|
546 {
|
|
547 printf("collection manager processing actions\n");
|
|
548 }
|
|
549
|
|
550 while (collection_manager_action_list != NULL && max > 0)
|
|
551 {
|
|
552 CollectManagerAction *action;
|
|
553 GList *work;
|
|
554
|
|
555 action = collection_manager_action_list->data;
|
|
556 work = collection_manager_entry_list;
|
|
557 while (work)
|
|
558 {
|
|
559 CollectManagerEntry *entry;
|
|
560
|
|
561 entry = work->data;
|
|
562 work = work->next;
|
|
563
|
|
564 if (action->type == COLLECTION_MANAGER_UPDATE)
|
|
565 {
|
|
566 entry->action_list = g_list_prepend(entry->action_list, action);
|
|
567 collect_manager_action_ref(action);
|
|
568 }
|
|
569 else if (action->oldpath && action->newpath &&
|
|
570 strcmp(action->newpath, entry->path) == 0)
|
|
571 {
|
|
572 /* convert action to standard add format */
|
|
573 g_free(action->newpath);
|
|
574 if (action->type == COLLECTION_MANAGER_ADD)
|
|
575 {
|
|
576 action->newpath = action->oldpath;
|
|
577 action->oldpath = NULL;
|
|
578 }
|
|
579 else if (action->type == COLLECTION_MANAGER_REMOVE)
|
|
580 {
|
|
581 action->newpath = NULL;
|
|
582 }
|
|
583
|
|
584 entry->action_list = g_list_prepend(entry->action_list, action);
|
|
585 collect_manager_action_ref(action);
|
|
586 }
|
|
587
|
|
588 max--;
|
|
589 }
|
|
590
|
|
591 if (action->type != COLLECTION_MANAGER_UPDATE &&
|
|
592 action->oldpath && action->newpath)
|
|
593 {
|
|
594 printf("collection manager failed to %s %s for collection %s\n",
|
|
595 (action->type == COLLECTION_MANAGER_ADD) ? "add" : "remove",
|
|
596 action->oldpath, action->newpath);
|
|
597 }
|
|
598
|
|
599 if (collection_manager_action_tail == collection_manager_action_list)
|
|
600 {
|
|
601 collection_manager_action_tail = NULL;
|
|
602 }
|
|
603 collection_manager_action_list = g_list_remove(collection_manager_action_list, action);
|
|
604 collect_manager_action_unref(action);
|
|
605 }
|
|
606 }
|
|
607
|
|
608 static gint collect_manager_process_entry(CollectManagerEntry *entry)
|
|
609 {
|
|
610 CollectionData *cd;
|
|
611 gint success;
|
|
612 GList *work;
|
|
613
|
|
614 if (!entry->action_list) return FALSE;
|
|
615
|
|
616 cd = collection_new(entry->path);
|
|
617 success = collection_load_private(cd, entry->path, FALSE, FALSE);
|
|
618
|
|
619 work = g_list_last(entry->action_list);
|
|
620 while (work)
|
|
621 {
|
|
622 CollectManagerAction *action;
|
|
623
|
|
624 action = work->data;
|
|
625 work = work->prev;
|
|
626
|
|
627 if (!action->oldpath)
|
|
628 {
|
|
629 /* add image */
|
|
630 if (collection_list_find(cd->list, action->newpath) == NULL)
|
|
631 {
|
|
632 collection_add_check(cd, action->newpath, FALSE, FALSE);
|
|
633 }
|
|
634 }
|
|
635 else if (action->newpath)
|
|
636 {
|
|
637 /* rename image */
|
|
638 while (collection_rename(cd, action->oldpath, action->newpath));
|
|
639 }
|
|
640 else
|
|
641 {
|
|
642 /* remove image */
|
|
643 while (collection_remove(cd, action->oldpath));
|
|
644 }
|
|
645 collect_manager_action_unref(action);
|
|
646 }
|
|
647
|
|
648 if (success && cd->changed)
|
|
649 {
|
|
650 collection_save_private(cd, entry->path);
|
|
651 if (debug) printf("collection manager updated: %s\n", entry->path);
|
|
652 }
|
|
653 collection_unref(cd);
|
|
654
|
|
655 g_list_free(entry->action_list);
|
|
656 entry->action_list = NULL;
|
|
657
|
|
658 return TRUE;
|
|
659 }
|
|
660
|
|
661 static gint collect_manager_process_entry_list(void)
|
|
662 {
|
|
663 GList *work;
|
|
664
|
|
665 work = collection_manager_entry_list;
|
|
666 while (work)
|
|
667 {
|
|
668 CollectManagerEntry *entry;
|
|
669
|
|
670 entry = work->data;
|
|
671 work = work->next;
|
|
672 if (collect_manager_process_entry(entry)) return TRUE;
|
|
673 }
|
|
674
|
|
675 return FALSE;
|
|
676 }
|
|
677
|
|
678 static gint collect_manager_process_cb(gpointer data)
|
|
679 {
|
|
680 if (collection_manager_action_list) collect_manager_refresh();
|
|
681 collect_manager_process_actions(COLLECT_MANAGER_ACTIONS_PER_IDLE);
|
|
682 if (collection_manager_action_list) return TRUE;
|
|
683
|
|
684 if (collect_manager_process_entry_list()) return TRUE;
|
|
685
|
|
686 if (debug) printf("collection manager is up to date\n");
|
|
687 return FALSE;
|
|
688 }
|
|
689
|
|
690 static gint collect_manager_timer_cb(gpointer data)
|
|
691 {
|
|
692 if (debug) printf("collection manager timer expired\n");
|
|
693
|
|
694 g_idle_add_full(G_PRIORITY_LOW, collect_manager_process_cb, NULL, NULL);
|
|
695
|
|
696 collection_manager_timer_id = -1;
|
|
697 return FALSE;
|
|
698 }
|
|
699
|
|
700 static void collect_manager_timer_push(gint stop)
|
|
701 {
|
|
702 if (collection_manager_timer_id != -1)
|
|
703 {
|
|
704 if (!stop) return;
|
|
705
|
|
706 g_source_remove(collection_manager_timer_id);
|
|
707 collection_manager_timer_id = -1;
|
|
708 }
|
|
709
|
|
710 if (!stop)
|
|
711 {
|
|
712 collection_manager_timer_id = g_timeout_add(COLLECT_MANAGER_FLUSH_DELAY,
|
|
713 collect_manager_timer_cb, NULL);
|
|
714 if (debug) printf("collection manager timer started\n");
|
|
715 }
|
|
716 }
|
|
717
|
|
718 static void collect_manager_add_action(CollectManagerAction *action)
|
|
719 {
|
|
720 if (!action) return;
|
|
721
|
|
722 /* we keep track of the list's tail to keep this a n(1) operation */
|
|
723
|
|
724 if (collection_manager_action_tail)
|
|
725 {
|
|
726 g_list_append(collection_manager_action_tail, action);
|
|
727 collection_manager_action_tail = collection_manager_action_tail->next;
|
|
728 }
|
|
729 else
|
|
730 {
|
|
731 collection_manager_action_list = g_list_append(collection_manager_action_list, action);
|
|
732 collection_manager_action_tail = collection_manager_action_list;
|
|
733 }
|
|
734
|
|
735 collect_manager_timer_push(FALSE);
|
|
736 }
|
|
737
|
|
738 void collect_manager_moved(const gchar *oldpath, const gchar *newpath)
|
|
739 {
|
|
740 CollectManagerAction *action;
|
|
741
|
|
742 action = collect_manager_action_new(oldpath, newpath, COLLECTION_MANAGER_UPDATE);
|
|
743 collect_manager_add_action(action);
|
|
744 }
|
|
745
|
|
746 void collect_manager_add(const gchar *path, const gchar *collection)
|
|
747 {
|
|
748 CollectManagerAction *action;
|
|
749 CollectWindow *cw;
|
|
750
|
|
751 if (!path || !collection) return;
|
|
752
|
|
753 cw = collection_window_find_by_path(collection);
|
|
754 if (cw)
|
|
755 {
|
|
756 if (collection_list_find(cw->cd->list, path) == NULL)
|
|
757 {
|
|
758 collection_add(cw->cd, path, FALSE);
|
|
759 }
|
|
760 return;
|
|
761 }
|
|
762
|
|
763 action = collect_manager_action_new(path, collection, COLLECTION_MANAGER_ADD);
|
|
764 collect_manager_add_action(action);
|
|
765 }
|
|
766
|
|
767 void collect_manager_remove(const gchar *path, const gchar *collection)
|
|
768 {
|
|
769 CollectManagerAction *action;
|
|
770 CollectWindow *cw;
|
|
771
|
|
772 if (!path || !collection) return;
|
|
773
|
|
774 cw = collection_window_find_by_path(collection);
|
|
775 if (cw)
|
|
776 {
|
|
777 while (collection_remove(cw->cd, path));
|
|
778 return;
|
|
779 }
|
|
780
|
|
781 action = collect_manager_action_new(path, collection, COLLECTION_MANAGER_REMOVE);
|
|
782 collect_manager_add_action(action);
|
|
783 }
|
|
784
|
|
785 void collect_manager_flush(void)
|
|
786 {
|
|
787 collect_manager_timer_push(TRUE);
|
|
788
|
|
789 if (debug) printf("collection manager flushing\n");
|
|
790 while (collect_manager_process_cb(NULL));
|
|
791 }
|
|
792
|