Rename mbe shrink_mode to expanded. Consistent with genlist naming.
[framework/uifw/elementary.git] / src / lib / elm_store.c
1 #include <Elementary.h>
2 #include <Elementary_Cursor.h>
3 #include "elm_priv.h"
4
5 #define ELM_STORE_MAGIC            0x3f89ea56
6 #define ELM_STORE_FILESYSTEM_MAGIC 0x3f89ea57
7 #define ELM_STORE_ITEM_MAGIC       0x5afe8c1d
8
9 struct _Elm_Store
10 {
11    EINA_MAGIC;
12    void           (*free)(Elm_Store *store);
13    struct {
14       void        (*free)(Elm_Store_Item *item);
15    } item;
16    Evas_Object   *genlist;
17    Ecore_Thread  *list_th;
18    Eina_Inlist   *items;
19    Eina_List     *realized;
20    int            realized_count;
21    int            cache_max;
22    struct {
23       struct {
24          Elm_Store_Item_List_Cb     func;
25          void                      *data;
26       } list;
27       struct {
28          Elm_Store_Item_Fetch_Cb    func;
29          void                      *data;
30       } fetch;
31       struct {
32          Elm_Store_Item_Unfetch_Cb  func;
33          void                      *data;
34       } unfetch;
35    } cb;
36    Eina_Bool sorted : 1;
37    Eina_Bool fetch_thread : 1;
38 };
39
40 struct _Elm_Store_Item
41 {
42    EINA_INLIST;
43    EINA_MAGIC;
44    Elm_Store                    *store;
45    Elm_Object_Item              *item;
46    Ecore_Thread                 *fetch_th;
47    Ecore_Job                    *eval_job;
48    const Elm_Store_Item_Mapping *mapping;
49    void                         *data;
50    Eina_Lock                     lock;
51    Eina_Bool                     live : 1;
52    Eina_Bool                     was_live : 1;
53    Eina_Bool                     realized : 1;
54    Eina_Bool                     fetched : 1;
55 };
56
57 struct _Elm_Store_Filesystem
58 {
59    Elm_Store base;
60    EINA_MAGIC;
61    const char *dir;
62 };
63
64 struct _Elm_Store_Item_Filesystem
65 {
66    Elm_Store_Item base;
67    const char *path;
68 };
69
70 static Elm_Genlist_Item_Class _store_item_class;
71
72 static void
73 _store_cache_trim(Elm_Store *st)
74 {
75    while ((st->realized ) &&
76           (((int)eina_list_count(st->realized) - st->realized_count)
77            > st->cache_max))
78      {
79         Elm_Store_Item *sti = st->realized->data;
80         if (sti->realized)
81           {
82              st->realized = eina_list_remove_list(st->realized, st->realized);
83              sti->realized = EINA_FALSE;
84           }
85         eina_lock_take(&sti->lock);
86         if (!sti->fetched)
87           {
88              eina_lock_release(&sti->lock);
89              if (sti->fetch_th)
90                {
91                   ecore_thread_cancel(sti->fetch_th);
92                   sti->fetch_th = NULL;
93                }
94              eina_lock_take(&sti->lock);
95           }
96         sti->fetched = EINA_FALSE;
97         eina_lock_release(&sti->lock);
98         if (st->cb.unfetch.func)
99           st->cb.unfetch.func(st->cb.unfetch.data, sti);
100         eina_lock_take(&sti->lock);
101         sti->data = NULL;
102         eina_lock_release(&sti->lock);
103      }
104 }
105
106 static void
107 _store_genlist_del(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
108 {
109    Elm_Store *st = data;
110    st->genlist = NULL;
111    if (st->list_th)
112      {
113         ecore_thread_cancel(st->list_th);
114         st->list_th = NULL;
115      }
116    eina_list_free(st->realized);
117    while (st->items)
118      {
119         Elm_Store_Item *sti = (Elm_Store_Item *)st->items;
120         if (sti->eval_job) ecore_job_del(sti->eval_job);
121         if (sti->fetch_th)
122           {
123              ecore_thread_cancel(sti->fetch_th);
124              sti->fetch_th = NULL;
125           }
126         if (sti->store->item.free) sti->store->item.free(sti);
127         if (sti->data)
128           {
129              if (st->cb.unfetch.func)
130                st->cb.unfetch.func(st->cb.unfetch.data, sti);
131              sti->data = NULL;
132           }
133         eina_lock_free(&sti->lock);
134         st->items = NULL;
135         free(sti);
136      }
137    // FIXME: kill threads and more
138 }
139
140 ////// **** WARNING ***********************************************************
141 ////   * This function runs inside a thread outside efl mainloop. Be careful! *
142 //     ************************************************************************
143 /* TODO: refactor lock part into core? this does not depend on filesystm part */
144 static void
145 _store_filesystem_fetch_do(void *data, Ecore_Thread *th __UNUSED__)
146 {
147    Elm_Store_Item *sti = data;
148    eina_lock_take(&sti->lock);
149    if (sti->data)
150      {
151         eina_lock_release(&sti->lock);
152         return;
153      }
154    if (!sti->fetched)
155      {
156         eina_lock_release(&sti->lock);
157         if (sti->store->cb.fetch.func)
158           sti->store->cb.fetch.func(sti->store->cb.fetch.data, sti);
159         eina_lock_take(&sti->lock);
160         sti->fetched = EINA_TRUE;
161      }
162    eina_lock_release(&sti->lock);
163 }
164 //     ************************************************************************
165 ////   * End of separate thread function.                                     *
166 ////// ************************************************************************
167 /* TODO: refactor lock part into core? this does not depend on filesystm part */
168 static void
169 _store_filesystem_fetch_end(void *data, Ecore_Thread *th)
170 {
171    Elm_Store_Item *sti = data;
172    eina_lock_take(&sti->lock);
173    if (sti->data) elm_genlist_item_update(sti->item);
174    eina_lock_release(&sti->lock);
175    if (th == sti->fetch_th) sti->fetch_th = NULL;
176 }
177
178 /* TODO: refactor lock part into core? this does not depend on filesystm part */
179 static void
180 _store_filesystem_fetch_cancel(void *data, Ecore_Thread *th)
181 {
182    Elm_Store_Item *sti = data;
183    eina_lock_take(&sti->lock);
184    if (th == sti->fetch_th) sti->fetch_th = NULL;
185    if (sti->data) elm_genlist_item_update(sti->item);
186    eina_lock_release(&sti->lock);
187 }
188
189 static void
190 _store_item_eval(void *data)
191 {
192    Elm_Store_Item *sti = data;
193    sti->eval_job = NULL;
194    if (sti->live == sti->was_live) return;
195    sti->was_live = sti->live;
196    if (sti->live)
197      {
198         _store_cache_trim(sti->store);
199         if (sti->realized)
200           sti->store->realized = eina_list_remove(sti->store->realized, sti);
201         sti->store->realized = eina_list_append(sti->store->realized, sti);
202         sti->realized = EINA_TRUE;
203         if ((sti->store->fetch_thread) && (!sti->fetch_th))
204           sti->fetch_th = ecore_thread_run(_store_filesystem_fetch_do,
205                                            _store_filesystem_fetch_end,
206                                            _store_filesystem_fetch_cancel,
207                                            sti);
208         else if ((!sti->store->fetch_thread))
209           {
210              _store_filesystem_fetch_do(sti, NULL);
211              _store_filesystem_fetch_end(sti, NULL);
212           }
213      }
214    else
215      {
216         if (sti->fetch_th)
217           {
218              ecore_thread_cancel(sti->fetch_th);
219              sti->fetch_th = NULL;
220           }
221         _store_cache_trim(sti->store);
222      }
223 }
224
225 static void
226 _store_genlist_item_realized(void *data, Evas_Object *obj __UNUSED__, void *event_info)
227 {
228    Elm_Store *st = data;
229    Elm_Object_Item *gli = event_info;
230    Elm_Store_Item *sti = elm_object_item_data_get(gli);
231    if (!sti) return;
232    st->realized_count++;
233    sti->live = EINA_TRUE;
234    if (sti->eval_job) ecore_job_del(sti->eval_job);
235    sti->eval_job = ecore_job_add(_store_item_eval, sti);
236 }
237
238 static void
239 _store_genlist_item_unrealized(void *data, Evas_Object *obj __UNUSED__, void *event_info)
240 {
241    Elm_Store *st = data;
242    Elm_Object_Item *gli = event_info;
243    Elm_Store_Item *sti = elm_object_item_data_get(gli);
244    if (!sti) return;
245    st->realized_count--;
246    sti->live = EINA_FALSE;
247    if (sti->eval_job) ecore_job_del(sti->eval_job);
248    sti->eval_job = ecore_job_add(_store_item_eval, sti);
249 }
250
251 static const Elm_Store_Item_Mapping *
252 _store_item_mapping_find(Elm_Store_Item *sti, const char *part)
253 {
254    const Elm_Store_Item_Mapping *m;
255
256    for (m = sti->mapping; m; m ++)
257      {
258         if (m->type == ELM_STORE_ITEM_MAPPING_NONE) break;
259         if (!strcmp(part, m->part)) return m;
260      }
261    return NULL;
262 }
263
264 static char *
265 _store_item_text_get(void *data, Evas_Object *obj __UNUSED__, const char *part)
266 {
267    Elm_Store_Item *sti = data;
268    const char *s = "";
269    eina_lock_take(&sti->lock);
270    if (sti->data)
271      {
272         const Elm_Store_Item_Mapping *m = _store_item_mapping_find(sti, part);
273         if (m)
274           {
275              switch (m->type)
276                {
277                 case ELM_STORE_ITEM_MAPPING_LABEL:
278                    s = *(char **)(((unsigned char *)sti->data) + m->offset);
279                    break;
280                 case ELM_STORE_ITEM_MAPPING_CUSTOM:
281                    if (m->details.custom.func)
282                      s = m->details.custom.func(sti->data, sti, part);
283                    break;
284                 default:
285                    break;
286                }
287           }
288      }
289    eina_lock_release(&sti->lock);
290    return s ? strdup(s) : NULL;
291 }
292
293 static Evas_Object *
294 _store_item_content_get(void *data, Evas_Object *obj, const char *part)
295 {
296    Elm_Store_Item *sti = data;
297    eina_lock_take(&sti->lock);
298    if (sti->data)
299      {
300         const Elm_Store_Item_Mapping *m = _store_item_mapping_find(sti, part);
301         if (m)
302           {
303              Evas_Object *ic = NULL;
304              const char *s = NULL;
305
306              switch (m->type)
307                {
308                 case ELM_STORE_ITEM_MAPPING_ICON:
309                    ic = elm_icon_add(obj);
310                    s = *(char **)(((unsigned char *)sti->data) + m->offset);
311                    elm_icon_order_lookup_set(ic, m->details.icon.lookup_order);
312                    evas_object_size_hint_aspect_set(ic,
313                                                     EVAS_ASPECT_CONTROL_VERTICAL,
314                                                     m->details.icon.w,
315                                                     m->details.icon.h);
316                    elm_icon_smooth_set(ic, m->details.icon.smooth);
317                    elm_icon_no_scale_set(ic, m->details.icon.no_scale);
318                    elm_icon_resizable_set(ic,
319                                       m->details.icon.scale_up,
320                                       m->details.icon.scale_down);
321                    if (s)
322                      {
323                         if (m->details.icon.standard_name)
324                           elm_icon_standard_set(ic, s);
325                         else
326                           elm_icon_file_set(ic, s, NULL);
327                      }
328                    break;
329                 case ELM_STORE_ITEM_MAPPING_PHOTO:
330                    ic = elm_icon_add(obj);
331                    s = *(char **)(((unsigned char *)sti->data) + m->offset);
332                    elm_photo_size_set(ic, m->details.photo.size);
333                    if (s)
334                      elm_photo_file_set(ic, s);
335                    break;
336                 case ELM_STORE_ITEM_MAPPING_CUSTOM:
337                    if (m->details.custom.func)
338                      ic = m->details.custom.func(sti->data, sti, part);
339                    break;
340                 default:
341                    break;
342                }
343              eina_lock_release(&sti->lock);
344              return ic;
345           }
346      }
347    eina_lock_release(&sti->lock);
348    return NULL;
349 }
350
351 static void
352 _store_item_del(void *data __UNUSED__, Evas_Object *obj __UNUSED__)
353 {
354 }
355
356 ////// **** WARNING ***********************************************************
357 ////   * This function runs inside a thread outside efl mainloop. Be careful! *
358 //     ************************************************************************
359 static int
360 _store_filesystem_sort_cb(void *d1, void *d2)
361 {
362    Elm_Store_Item_Info *info1 = d1, *info2 = d2;
363    if ((!info1->sort_id) || (!info2->sort_id)) return 0;
364    return strcoll(info1->sort_id, info2->sort_id);
365 }
366
367 static void
368 _store_filesystem_list_do(void *data, Ecore_Thread *th __UNUSED__)
369 {
370    Elm_Store_Filesystem *st = data;
371    Eina_Iterator *it;
372    const Eina_File_Direct_Info *finf;
373    Eina_List *sorted = NULL;
374    Elm_Store_Item_Info_Filesystem *info;
375
376    // FIXME: need a way to abstract the open, list, feed items from list
377    // and maybe get initial sortable key vals etc.
378    it = eina_file_stat_ls(st->dir);
379    if (!it) return;
380    EINA_ITERATOR_FOREACH(it, finf)
381      {
382         Eina_Bool ok;
383         size_t pathsz = finf->path_length + 1;
384
385         if (finf->path[finf->name_start] == '.') continue ;
386
387         info = calloc(1, sizeof(Elm_Store_Item_Info_Filesystem) + pathsz);
388         if (!info) continue;
389         info->path = ((char *)info) + sizeof(Elm_Store_Item_Info_Filesystem);
390         memcpy(info->path, finf->path, pathsz);
391         ok = EINA_TRUE;
392         if (st->base.cb.list.func)
393           ok = st->base.cb.list.func(st->base.cb.list.data, &info->base);
394         if (ok)
395           {
396              if (!st->base.sorted) ecore_thread_feedback(th, info);
397              else sorted = eina_list_append(sorted, info);
398           }
399         else
400           {
401              if (info->base.sort_id) free(info->base.sort_id);
402              free(info);
403           }
404         if (ecore_thread_check(th)) break;
405      }
406    eina_iterator_free(it);
407    if (sorted)
408      {
409         sorted = eina_list_sort(sorted, 0,
410                                 EINA_COMPARE_CB(_store_filesystem_sort_cb));
411         EINA_LIST_FREE(sorted, info)
412           {
413              if (!ecore_thread_check(th)) ecore_thread_feedback(th, info);
414           }
415      }
416 }
417 //     ************************************************************************
418 ////   * End of separate thread function.                                     *
419 ////// ************************************************************************
420
421 static void
422 _store_filesystem_list_end(void *data, Ecore_Thread *th)
423 {
424    Elm_Store *st = data;
425    if (th == st->list_th) st->list_th = NULL;
426 }
427
428 static void
429 _store_filesystem_list_cancel(void *data, Ecore_Thread *th)
430 {
431    Elm_Store *st = data;
432    if (th == st->list_th) st->list_th = NULL;
433 }
434
435 static void
436 _store_filesystem_list_update(void *data, Ecore_Thread *th __UNUSED__, void *msg)
437 {
438    Elm_Store *st = data;
439    Elm_Store_Item_Filesystem *sti;
440    Elm_Genlist_Item_Class *itc;
441    Elm_Store_Item_Info_Filesystem *info = msg;
442
443    sti = calloc(1, sizeof(Elm_Store_Item_Filesystem));
444    if (!sti) goto done;
445    eina_lock_new(&sti->base.lock);
446    EINA_MAGIC_SET(&(sti->base), ELM_STORE_ITEM_MAGIC);
447    sti->base.store = st;
448    sti->base.data = info->base.data;
449    sti->base.mapping = info->base.mapping;
450    sti->path = eina_stringshare_add(info->path);
451
452    itc = info->base.item_class;
453    if (!itc) itc = &_store_item_class;
454    else
455      {
456         itc->func.text_get = _store_item_text_get;
457         itc->func.content_get  = _store_item_content_get;
458         itc->func.state_get = NULL; // FIXME: support state gets later
459         itc->func.del       = _store_item_del;
460      }
461
462    // FIXME: handle being a parent (tree)
463    sti->base.item = elm_genlist_item_append(st->genlist, itc,
464                                             sti/* item data */,
465                                             NULL/* parent */,
466                                             ELM_GENLIST_ITEM_NONE,
467                                             NULL/* func */,
468                                             NULL/* func data */);
469    st->items = eina_inlist_append(st->items, (Eina_Inlist *)sti);
470 done:
471    if (info->base.sort_id) free(info->base.sort_id);
472    free(info);
473 }
474
475 // public api calls
476 static Elm_Store *
477 _elm_store_new(size_t size)
478 {
479    Elm_Store *st = calloc(1, size);
480    EINA_SAFETY_ON_NULL_RETURN_VAL(st, NULL);
481
482    // TODO: BEGIN - move to elm_store_init()
483    eina_magic_string_set(ELM_STORE_MAGIC, "Elm_Store");
484    eina_magic_string_set(ELM_STORE_FILESYSTEM_MAGIC, "Elm_Store_Filesystem");
485    eina_magic_string_set(ELM_STORE_ITEM_MAGIC, "Elm_Store_Item");
486    // setup default item class (always the same) if list cb doesnt provide one
487    _store_item_class.item_style = "default";
488    _store_item_class.func.text_get = _store_item_text_get;
489    _store_item_class.func.content_get  = _store_item_content_get;
490    _store_item_class.func.state_get = NULL; // FIXME: support state gets later
491    _store_item_class.func.del       = _store_item_del;
492    // TODO: END - move to elm_store_init()
493
494    EINA_MAGIC_SET(st, ELM_STORE_MAGIC);
495    st->cache_max = 128;
496    st->fetch_thread = EINA_TRUE;
497    return st;
498 }
499 #define elm_store_new(type) (type*)_elm_store_new(sizeof(type))
500
501 static void
502 _elm_store_filesystem_free(Elm_Store *store)
503 {
504    Elm_Store_Filesystem *st = (Elm_Store_Filesystem *)store;
505    eina_stringshare_del(st->dir);
506 }
507
508 static void
509 _elm_store_filesystem_item_free(Elm_Store_Item *item)
510 {
511    Elm_Store_Item_Filesystem *sti = (Elm_Store_Item_Filesystem *)item;
512    eina_stringshare_del(sti->path);
513 }
514
515 EAPI Elm_Store *
516 elm_store_filesystem_new(void)
517 {
518    Elm_Store_Filesystem *st = elm_store_new(Elm_Store_Filesystem);
519    EINA_SAFETY_ON_NULL_RETURN_VAL(st, NULL);
520
521    EINA_MAGIC_SET(st, ELM_STORE_FILESYSTEM_MAGIC);
522    st->base.free = _elm_store_filesystem_free;
523    st->base.item.free = _elm_store_filesystem_item_free;
524
525    return &st->base;
526 }
527
528 EAPI void
529 elm_store_free(Elm_Store *st)
530 {
531    void (*item_free)(Elm_Store_Item *);
532    if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return;
533    if (st->list_th)
534      {
535         ecore_thread_cancel(st->list_th);
536         st->list_th = NULL;
537      }
538    eina_list_free(st->realized);
539    item_free = st->item.free;
540    while (st->items)
541      {
542         Elm_Store_Item *sti = (Elm_Store_Item *)st->items;
543         if (sti->eval_job) ecore_job_del(sti->eval_job);
544         if (sti->fetch_th)
545           {
546              ecore_thread_cancel(sti->fetch_th);
547              sti->fetch_th = NULL;
548           }
549         if (item_free) item_free(sti);
550         if (sti->data)
551           {
552              if (st->cb.unfetch.func)
553                st->cb.unfetch.func(st->cb.unfetch.data, sti);
554              sti->data = NULL;
555           }
556         eina_lock_free(&sti->lock);
557         free(sti);
558      }
559    if (st->genlist)
560      {
561         evas_object_event_callback_del_full(st->genlist, EVAS_CALLBACK_DEL, _store_genlist_del, st);
562         evas_object_smart_callback_del(st->genlist, "realized", _store_genlist_item_realized);
563         evas_object_smart_callback_del(st->genlist, "unrealized", _store_genlist_item_unrealized);
564         elm_genlist_clear(st->genlist);
565         st->genlist = NULL;
566      }
567    if (st->free) st->free(st);
568    free(st);
569 }
570
571 EAPI void
572 elm_store_target_genlist_set(Elm_Store *st, Evas_Object *obj)
573 {
574    if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return;
575    if (st->genlist == obj) return;
576    if (st->genlist)
577      {
578         evas_object_event_callback_del_full(st->genlist, EVAS_CALLBACK_DEL, _store_genlist_del, st);
579         evas_object_smart_callback_del(st->genlist, "realized", _store_genlist_item_realized);
580         evas_object_smart_callback_del(st->genlist, "unrealized", _store_genlist_item_unrealized);
581         elm_genlist_clear(st->genlist);
582      }
583    st->genlist = obj;
584    if (!st->genlist) return;
585    evas_object_smart_callback_add(st->genlist, "realized", _store_genlist_item_realized, st);
586    evas_object_smart_callback_add(st->genlist, "unrealized", _store_genlist_item_unrealized, st);
587    evas_object_event_callback_add(st->genlist, EVAS_CALLBACK_DEL, _store_genlist_del, st);
588    elm_genlist_clear(st->genlist);
589 }
590
591 EAPI void
592 elm_store_filesystem_directory_set(Elm_Store *store, const char *dir)
593 {
594    Elm_Store_Filesystem *st = (Elm_Store_Filesystem *)store;
595    if (!EINA_MAGIC_CHECK(store, ELM_STORE_MAGIC)) return;
596    if (!EINA_MAGIC_CHECK(st, ELM_STORE_FILESYSTEM_MAGIC)) return;
597    if (store->list_th)
598      {
599         ecore_thread_cancel(store->list_th);
600         store->list_th = NULL;
601      }
602    if (!eina_stringshare_replace(&st->dir, dir)) return;
603    store->list_th = ecore_thread_feedback_run(_store_filesystem_list_do,
604                                               _store_filesystem_list_update,
605                                               _store_filesystem_list_end,
606                                               _store_filesystem_list_cancel,
607                                               st, EINA_TRUE);
608 }
609
610 EAPI const char *
611 elm_store_filesystem_directory_get(const Elm_Store *store)
612 {
613    const Elm_Store_Filesystem *st = (const Elm_Store_Filesystem *)store;
614    if (!EINA_MAGIC_CHECK(store, ELM_STORE_MAGIC)) return NULL;
615    if (!EINA_MAGIC_CHECK(st, ELM_STORE_FILESYSTEM_MAGIC)) return NULL;
616    return st->dir;
617 }
618
619 EAPI void
620 elm_store_cache_set(Elm_Store *st, int max)
621 {
622    if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return;
623    if (max < 0) max = 0;
624    st->cache_max = max;
625    _store_cache_trim(st);
626 }
627
628 EAPI int
629 elm_store_cache_get(const Elm_Store *st)
630 {
631    if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return 0;
632    return st->cache_max;
633 }
634
635 EAPI void
636 elm_store_list_func_set(Elm_Store *st, Elm_Store_Item_List_Cb func, const void *data)
637 {
638    if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return;
639    st->cb.list.func = func;
640    st->cb.list.data = (void *)data;
641 }
642
643 EAPI void
644 elm_store_fetch_func_set(Elm_Store *st, Elm_Store_Item_Fetch_Cb func, const void *data)
645 {
646    if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return;
647    st->cb.fetch.func = func;
648    st->cb.fetch.data = (void *)data;
649 }
650
651 EAPI void
652 elm_store_fetch_thread_set(Elm_Store *st, Eina_Bool use_thread)
653 {
654    if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return;
655    st->fetch_thread = !!use_thread;
656 }
657
658 EAPI Eina_Bool
659 elm_store_fetch_thread_get(const Elm_Store *st)
660 {
661    if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return EINA_FALSE;
662    return st->fetch_thread;
663 }
664
665 EAPI void
666 elm_store_unfetch_func_set(Elm_Store *st, Elm_Store_Item_Unfetch_Cb func, const void *data)
667 {
668    if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return;
669    st->cb.unfetch.func = func;
670    st->cb.unfetch.data = (void *)data;
671 }
672
673 EAPI void
674 elm_store_sorted_set(Elm_Store *st, Eina_Bool sorted)
675 {
676    if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return;
677    st->sorted = sorted;
678 }
679
680 EAPI Eina_Bool
681 elm_store_sorted_get(const Elm_Store *st)
682 {
683    if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return EINA_FALSE;
684    return st->sorted;
685 }
686
687 EAPI void
688 elm_store_item_data_set(Elm_Store_Item *sti, void *data)
689 {
690    if (!EINA_MAGIC_CHECK(sti, ELM_STORE_ITEM_MAGIC)) return;
691    eina_lock_take(&sti->lock);
692    sti->data = data;
693    eina_lock_release(&sti->lock);
694 }
695
696 EAPI void *
697 elm_store_item_data_get(Elm_Store_Item *sti)
698 {
699    if (!EINA_MAGIC_CHECK(sti, ELM_STORE_ITEM_MAGIC)) return NULL;
700    void *d;
701    eina_lock_take(&sti->lock);
702    d = sti->data;
703    eina_lock_release(&sti->lock);
704    return d;
705 }
706
707 EAPI const Elm_Store *
708 elm_store_item_store_get(const Elm_Store_Item *sti)
709 {
710    if (!EINA_MAGIC_CHECK(sti, ELM_STORE_ITEM_MAGIC)) return NULL;
711    // dont need lock
712    return sti->store;
713 }
714
715 EAPI const Elm_Object_Item *
716 elm_store_item_genlist_item_get(const Elm_Store_Item *sti)
717 {
718    if (!EINA_MAGIC_CHECK(sti, ELM_STORE_ITEM_MAGIC)) return NULL;
719    // dont need lock
720    return sti->item;
721 }
722
723 EAPI const char *
724 elm_store_item_filesystem_path_get(const Elm_Store_Item *item)
725 {
726    Elm_Store_Item_Filesystem *sti = (Elm_Store_Item_Filesystem *)item;
727    Elm_Store_Filesystem *st;
728    if (!EINA_MAGIC_CHECK(item, ELM_STORE_ITEM_MAGIC)) return NULL;
729    if (!EINA_MAGIC_CHECK(item->store, ELM_STORE_MAGIC)) return NULL;
730    /* ensure we're dealing with filesystem item */
731    st = (Elm_Store_Filesystem *)item->store;
732    if (!EINA_MAGIC_CHECK(st, ELM_STORE_FILESYSTEM_MAGIC)) return NULL;
733    // dont need lock
734    return sti->path;
735 }