els_icon/elm_image - added features to aspect_ratio changeable
[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 #ifndef EFL_HAVE_THREADS
6 # error "No thread support. Required."
7 #endif
8
9 #ifdef EFL_HAVE_POSIX_THREADS
10 # include <pthread.h>
11 # define LK(x)  pthread_mutex_t x
12 # define LKI(x) pthread_mutex_init(&(x), NULL);
13 # define LKD(x) pthread_mutex_destroy(&(x));
14 # define LKL(x) pthread_mutex_lock(&(x));
15 # define LKU(x) pthread_mutex_unlock(&(x));
16 #else /* EFL_HAVE_WIN32_THREADS */
17 # define WIN32_LEAN_AND_MEAN
18 # include <windows.h>
19 # undef WIN32_LEAN_AND_MEAN
20 # define LK(x)  HANDLE x
21 # define LKI(x) x = CreateMutex(NULL, FALSE, NULL)
22 # define LKD(x) CloseHandle(x)
23 # define LKL(x) WaitForSingleObject(x, INFINITE)
24 # define LKU(x) ReleaseMutex(x)
25 #endif
26
27 #define ELM_STORE_MAGIC            0x3f89ea56
28 #define ELM_STORE_FILESYSTEM_MAGIC 0x3f89ea57
29 #define ELM_STORE_DBSYSTEM_MAGIC   0x3f89ea58
30 #define ELM_STORE_ITEM_MAGIC       0x5afe8c1d
31 #define CACHE_COUNT                127
32 #define SCREEN_ITEM_COUNT    10
33
34 struct _Elm_Store
35 {
36    EINA_MAGIC;
37    void         (*free)(Elm_Store *store);
38    struct {
39         void        (*free)(Elm_Store_Item *item);
40    } item;
41    Evas_Object   *genlist;
42    Ecore_Thread  *list_th;
43    Eina_Inlist   *items;
44    Eina_List     *realized;
45    int            realized_count;
46    int            cache_max;
47    int            start_fetch_index;
48    int            end_fetch_index;
49    int            item_count;
50    int            total_item_count;
51    int            block_count;
52    int            type;
53    Eina_List     *header_items;
54    struct {
55         struct {
56              Elm_Store_Item_List_Cb     func;
57              void                      *data;
58         } list;
59         struct {
60              Elm_Store_Item_Fetch_Cb    func;
61              void                      *data;
62         } fetch;
63         struct {
64              Elm_Store_Item_Unfetch_Cb  func;
65              void                      *data;
66         } unfetch;
67         struct {
68              Elm_Store_Item_Select_Cb func;
69              void                    *data;
70         } item_select;
71         struct {
72              Elm_Store_Item_Sort_Cb func;
73              void                  *data;
74         } item_sort;
75         struct {
76              Elm_Store_Item_Free_Cb func;
77              void                  *data;
78         } item_free;
79    } cb;
80    Eina_Bool      sorted : 1;
81    Eina_Bool      fetch_thread : 1;
82    Eina_Bool      multi_load : 1;
83    Eina_Bool      live : 1;
84 };
85
86 struct _Elm_Store_Item
87 {
88    EINA_INLIST;
89    EINA_MAGIC;
90    Elm_Store                    *store;
91    Elm_Genlist_Item             *item;
92    Ecore_Thread                 *fetch_th;
93    Ecore_Job                    *eval_job;
94    const Elm_Store_Item_Mapping *mapping;
95    void                         *data;
96    Elm_Store_Item_Info          *item_info;
97    LK(lock);
98    Eina_Bool                     live : 1;
99    Eina_Bool                     was_live : 1;
100    Eina_Bool                     realized : 1;
101    Eina_Bool                     fetched : 1;
102 };
103
104 struct _Elm_Store_Filesystem
105 {
106    Elm_Store   base;
107    EINA_MAGIC;
108    const char *dir;
109 };
110
111 struct _Elm_Store_Item_Filesystem
112 {
113    Elm_Store_Item base;
114    const char    *path;
115 };
116
117 struct _Elm_Store_DBsystem
118 {
119    Elm_Store   base;
120    EINA_MAGIC;
121    void       *p_db;
122 };
123
124 typedef enum
125 {
126    ELM_STORE_ITEM_SORT_LOW = -1,
127    ELM_STORE_ITEM_SORT_SAME = 0,
128    ELM_STORE_ITEM_SORT_HIGH = 1,
129    ELM_STORE_ITEM_SORT_UNKNOWN = 2,
130    ELM_STORE_ITEM_SORT_LAST
131 } Elm_Store_Item_Sort_Type;
132
133 static Elm_Genlist_Item_Class _store_item_class;
134
135 static char *_item_label_get(void *data, Evas_Object *obj __UNUSED__, const char *part);
136 static Evas_Object *_item_icon_get(void *data, Evas_Object *obj, const char *part);
137 static void _item_del(void *data __UNUSED__, Evas_Object *obj __UNUSED__);
138 static void _store_free(Elm_Store *st);
139 static void _item_free(Elm_Store_Item *sti);
140 static void _item_realized(void *data, Evas_Object *obj __UNUSED__, void *event_info);
141 static void _item_unrealized(void *data, Evas_Object *obj __UNUSED__, void *event_info);
142 static void _genlist_del(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__);
143 static Elm_Store_Item *_item_unfetch(Elm_Store *st, int index);
144
145 static void
146 _store_cache_trim(Elm_Store *st)
147 {
148    while ((st->realized ) &&
149           (((int)eina_list_count(st->realized) - st->realized_count)
150            > st->cache_max))
151      {
152         Elm_Store_Item *sti = st->realized->data;
153         if (sti->realized)
154           {
155              st->realized = eina_list_remove_list(st->realized, st->realized);
156              sti->realized = EINA_FALSE;
157           }
158         LKL(sti->lock);
159         if (!sti->fetched)
160           {
161              LKU(sti->lock);
162              if (sti->fetch_th)
163                {
164                   ecore_thread_cancel(sti->fetch_th);
165                   sti->fetch_th = NULL;
166                }
167              LKL(sti->lock);
168           }
169         sti->fetched = EINA_FALSE;
170         LKU(sti->lock);
171         if (st->cb.unfetch.func)
172           st->cb.unfetch.func(st->cb.unfetch.data, sti, NULL);
173         LKL(sti->lock);
174         sti->data = NULL;
175         LKU(sti->lock);
176      }
177 }
178
179 static void
180 _store_genlist_del(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
181 {
182    Elm_Store *st = data;
183    st->genlist = NULL;
184    if (st->list_th)
185      {
186         ecore_thread_cancel(st->list_th);
187         st->list_th = NULL;
188      }
189    eina_list_free(st->realized);
190    while (st->items)
191      {
192         Elm_Store_Item *sti = (Elm_Store_Item *)st->items;
193         if (sti->eval_job) ecore_job_del(sti->eval_job);
194         if (sti->fetch_th)
195           {
196              ecore_thread_cancel(sti->fetch_th);
197              sti->fetch_th = NULL;
198           }
199         if (sti->store->item.free) sti->store->item.free(sti);
200         if (sti->data)
201           {
202              if (st->cb.unfetch.func)
203                st->cb.unfetch.func(st->cb.unfetch.data, sti, NULL);
204              sti->data = NULL;
205           }
206         LKD(sti->lock);
207         free(sti);
208      }
209    // FIXME: kill threads and more
210 }
211
212 ////// **** WARNING ***********************************************************
213 ////   * This function runs inside a thread outside efl mainloop. Be careful! *
214 //     ************************************************************************
215 /* TODO: refactor lock part into core? this does not depend on filesystm part */
216 static void
217 _store_filesystem_fetch_do(void *data, Ecore_Thread *th __UNUSED__)
218 {
219    Elm_Store_Item *sti = data;
220    LKL(sti->lock);
221    if (sti->data)
222      {
223         LKU(sti->lock);
224         return;
225      }
226    if (!sti->fetched)
227      {
228         LKU(sti->lock);
229         if (sti->store->cb.fetch.func)
230           sti->store->cb.fetch.func(sti->store->cb.fetch.data, sti, NULL);
231         LKL(sti->lock);
232         sti->fetched = EINA_TRUE;
233      }
234    LKU(sti->lock);
235 }
236 //     ************************************************************************
237 ////   * End of separate thread function.                                     *
238 ////// ************************************************************************
239 /* TODO: refactor lock part into core? this does not depend on filesystm part */
240 static void
241 _store_filesystem_fetch_end(void *data, Ecore_Thread *th)
242 {
243    Elm_Store_Item *sti = data;
244    LKL(sti->lock);
245    if (sti->data) elm_genlist_item_update(sti->item);
246    LKU(sti->lock);
247    if (th == sti->fetch_th) sti->fetch_th = NULL;
248 }
249
250 /* TODO: refactor lock part into core? this does not depend on filesystm part */
251 static void
252 _store_filesystem_fetch_cancel(void *data, Ecore_Thread *th)
253 {
254    Elm_Store_Item *sti = data;
255    LKL(sti->lock);
256    if (th == sti->fetch_th) sti->fetch_th = NULL;
257    if (sti->data) elm_genlist_item_update(sti->item);
258    LKU(sti->lock);
259 }
260
261 static void
262 _store_item_eval(void *data)
263 {
264    Elm_Store_Item *sti = data;
265    sti->eval_job = NULL;
266    if (sti->live == sti->was_live) return;
267    sti->was_live = sti->live;
268    if (sti->live)
269      {
270         _store_cache_trim(sti->store);
271         if (sti->realized)
272           sti->store->realized = eina_list_remove(sti->store->realized, sti);
273         sti->store->realized = eina_list_append(sti->store->realized, sti);
274         sti->realized = EINA_TRUE;
275         if ((sti->store->fetch_thread) && (!sti->fetch_th))
276           sti->fetch_th = ecore_thread_run(_store_filesystem_fetch_do,
277                                            _store_filesystem_fetch_end,
278                                            _store_filesystem_fetch_cancel,
279                                            sti);
280         else if ((!sti->store->fetch_thread))
281           {
282              _store_filesystem_fetch_do(sti, NULL);
283              _store_filesystem_fetch_end(sti, NULL);
284           }
285      }
286    else
287      {
288         if (sti->fetch_th)
289           {
290              ecore_thread_cancel(sti->fetch_th);
291              sti->fetch_th = NULL;
292           }
293         _store_cache_trim(sti->store);
294      }
295 }
296
297 static void
298 _store_genlist_item_realized(void *data, Evas_Object *obj __UNUSED__, void *event_info)
299 {
300    Elm_Store *st = data;
301    Elm_Genlist_Item *gli = event_info;
302    Elm_Store_Item *sti = elm_genlist_item_data_get(gli);
303    if (!sti) return;
304    st->realized_count++;
305    sti->live = EINA_TRUE;
306    if (sti->eval_job) ecore_job_del(sti->eval_job);
307    sti->eval_job = ecore_job_add(_store_item_eval, sti);
308 }
309
310 static void
311 _store_genlist_item_unrealized(void *data, Evas_Object *obj __UNUSED__, void *event_info)
312 {
313    Elm_Store *st = data;
314    Elm_Genlist_Item *gli = event_info;
315    Elm_Store_Item *sti = elm_genlist_item_data_get(gli);
316    if (!sti) return;
317    st->realized_count--;
318    sti->live = EINA_FALSE;
319    if (sti->eval_job) ecore_job_del(sti->eval_job);
320    sti->eval_job = ecore_job_add(_store_item_eval, sti);
321 }
322
323 static const Elm_Store_Item_Mapping *
324 _store_item_mapping_find(Elm_Store_Item *sti, const char *part)
325 {
326    const Elm_Store_Item_Mapping *m;
327
328    for (m = sti->mapping; m; m ++)
329      {
330         if (m->type == ELM_STORE_ITEM_MAPPING_NONE) break;
331         if (!strcmp(part, m->part)) return m;
332      }
333    return NULL;
334 }
335
336 static char *
337 _store_item_label_get(void *data, Evas_Object *obj __UNUSED__, const char *part)
338 {
339    Elm_Store_Item *sti = data;
340    const char *s = "";
341    LKL(sti->lock);
342    if (sti->data)
343      {
344         const Elm_Store_Item_Mapping *m = _store_item_mapping_find(sti, part);
345         if (m)
346           {
347              switch (m->type)
348                {
349                 case ELM_STORE_ITEM_MAPPING_LABEL:
350                    s = *(char **)(((unsigned char *)sti->data) + m->offset);
351                    break;
352                 case ELM_STORE_ITEM_MAPPING_CUSTOM:
353                    if (m->details.custom.func)
354                      s = m->details.custom.func(sti->data, sti, part);
355                    break;
356                 default:
357                    break;
358                }
359           }
360      }
361    LKU(sti->lock);
362    return strdup(s);
363 }
364
365 static Evas_Object *
366 _store_item_icon_get(void *data, Evas_Object *obj, const char *part)
367 {
368    Elm_Store_Item *sti = data;
369    LKL(sti->lock);
370    if (sti->data)
371      {
372         const Elm_Store_Item_Mapping *m = _store_item_mapping_find(sti, part);
373         if (m)
374           {
375              Evas_Object *ic = NULL;
376              const char *s = NULL;
377
378              switch (m->type)
379                {
380                 case ELM_STORE_ITEM_MAPPING_ICON:
381                    ic = elm_icon_add(obj);
382                    s = *(char **)(((unsigned char *)sti->data) + m->offset);
383                    elm_icon_order_lookup_set(ic, m->details.icon.lookup_order);
384                    evas_object_size_hint_aspect_set(ic,
385                                                     EVAS_ASPECT_CONTROL_VERTICAL,
386                                                     m->details.icon.w,
387                                                     m->details.icon.h);
388                    elm_icon_smooth_set(ic, m->details.icon.smooth);
389                    elm_icon_no_scale_set(ic, m->details.icon.no_scale);
390                    elm_icon_scale_set(ic,
391                                       m->details.icon.scale_up,
392                                       m->details.icon.scale_down);
393                    if (s)
394                      {
395                         if (m->details.icon.standard_name)
396                           elm_icon_standard_set(ic, s);
397                         else
398                           elm_icon_file_set(ic, s, NULL);
399                      }
400                    break;
401                 case ELM_STORE_ITEM_MAPPING_PHOTO:
402                    ic = elm_icon_add(obj);
403                    s = *(char **)(((unsigned char *)sti->data) + m->offset);
404                    elm_photo_size_set(ic, m->details.photo.size);
405                    if (s)
406                      elm_photo_file_set(ic, s);
407                    break;
408                 case ELM_STORE_ITEM_MAPPING_CUSTOM:
409                    if (m->details.custom.func)
410                      ic = m->details.custom.func(sti->data, sti, part);
411                    break;
412                 default:
413                    break;
414                }
415              LKU(sti->lock);
416              return ic;
417           }
418      }
419    LKU(sti->lock);
420    return NULL;
421 }
422
423 static void
424 _store_item_del(void *data __UNUSED__, Evas_Object *obj __UNUSED__)
425 {
426 }
427
428 ////// **** WARNING ***********************************************************
429 ////   * This function runs inside a thread outside efl mainloop. Be careful! *
430 //     ************************************************************************
431 static int
432 _store_filesystem_sort_cb(void *d1, void *d2)
433 {
434    Elm_Store_Item_Info *info1 = d1, *info2 = d2;
435    if ((!info1->sort_id) || (!info2->sort_id)) return 0;
436    return strcoll(info1->sort_id, info2->sort_id);
437 }
438
439 static void
440 _store_filesystem_list_do(void *data, Ecore_Thread *th __UNUSED__)
441 {
442    Elm_Store_Filesystem *st = data;
443    Eina_Iterator *it;
444    const Eina_File_Direct_Info *finf;
445    Eina_List *sorted = NULL;
446    Elm_Store_Item_Info_Filesystem *info;
447
448    // FIXME: need a way to abstract the open, list, feed items from list
449    // and maybe get initial sortable key vals etc.
450    it = eina_file_stat_ls(st->dir);
451    if (!it) return;
452    EINA_ITERATOR_FOREACH(it, finf)
453      {
454         Eina_Bool ok;
455         size_t pathsz = finf->path_length + 1;
456
457         info = calloc(1, sizeof(Elm_Store_Item_Info_Filesystem) + pathsz);
458         if (!info) continue;
459         info->path = ((char *)info) + sizeof(Elm_Store_Item_Info_Filesystem);
460         memcpy(info->path, finf->path, pathsz);
461         ok = EINA_TRUE;
462         if (st->base.cb.list.func)
463           ok = st->base.cb.list.func(st->base.cb.list.data, &info->base);
464         if (ok)
465           {
466              if (!st->base.sorted) ecore_thread_feedback(th, info);
467              else sorted = eina_list_append(sorted, info);
468           }
469         else
470           {
471              if (info->base.sort_id) free(info->base.sort_id);
472              free(info);
473           }
474         if (ecore_thread_check(th)) break;
475      }
476    eina_iterator_free(it);
477    if (sorted)
478      {
479         sorted = eina_list_sort(sorted, 0,
480                                 EINA_COMPARE_CB(_store_filesystem_sort_cb));
481         EINA_LIST_FREE(sorted, info)
482           {
483              if (!ecore_thread_check(th)) ecore_thread_feedback(th, info);
484           }
485      }
486 }
487 //     ************************************************************************
488 ////   * End of separate thread function.                                     *
489 ////// ************************************************************************
490
491 static void
492 _store_filesystem_list_end(void *data, Ecore_Thread *th)
493 {
494    Elm_Store *st = data;
495    if (th == st->list_th) st->list_th = NULL;
496 }
497
498 static void
499 _store_filesystem_list_cancel(void *data, Ecore_Thread *th)
500 {
501    Elm_Store *st = data;
502    if (th == st->list_th) st->list_th = NULL;
503 }
504
505 static void
506 _store_filesystem_list_update(void *data, Ecore_Thread *th __UNUSED__, void *msg)
507 {
508    Elm_Store *st = data;
509    Elm_Store_Item_Filesystem *sti;
510    Elm_Genlist_Item_Class *itc;
511    Elm_Store_Item_Info_Filesystem *info = msg;
512
513    sti = calloc(1, sizeof(Elm_Store_Item_Filesystem));
514    if (!sti) goto done;
515    LKI(sti->base.lock);
516    EINA_MAGIC_SET(&(sti->base), ELM_STORE_ITEM_MAGIC);
517    sti->base.store = st;
518    sti->base.data = info->base.data;
519    sti->base.mapping = info->base.mapping;
520    sti->path = eina_stringshare_add(info->path);
521
522    itc = info->base.item_class;
523    if (!itc) itc = &_store_item_class;
524    else
525      {
526         itc->func.label_get = (GenlistItemLabelGetFunc)_store_item_label_get;
527         itc->func.icon_get  = (GenlistItemIconGetFunc)_store_item_icon_get;
528         itc->func.state_get = NULL; // FIXME: support state gets later
529         itc->func.del = (GenlistItemDelFunc)_store_item_del;
530      }
531
532    // FIXME: handle being a parent (tree)
533    sti->base.item = elm_genlist_item_append(st->genlist, itc,
534                                             sti/* item data */,
535                                             NULL/* parent */,
536                                             ELM_GENLIST_ITEM_NONE,
537                                             NULL/* func */,
538                                             NULL/* func data */);
539    st->items = eina_inlist_append(st->items, (Eina_Inlist *)sti);
540 done:
541    if (info->base.sort_id) free(info->base.sort_id);
542    free(info);
543 }
544
545 // public api calls
546 static Elm_Store *
547 _elm_store_new(size_t size)
548 {
549    Elm_Store *st = calloc(1, size);
550    EINA_SAFETY_ON_NULL_RETURN_VAL(st, NULL);
551
552    // TODO: BEGIN - move to elm_store_init()
553    eina_magic_string_set(ELM_STORE_MAGIC, "Elm_Store");
554    eina_magic_string_set(ELM_STORE_FILESYSTEM_MAGIC, "Elm_Store_Filesystem");
555    eina_magic_string_set(ELM_STORE_ITEM_MAGIC, "Elm_Store_Item");
556    // setup default item class (always the same) if list cb doesnt provide one
557    _store_item_class.item_style = "default";
558    _store_item_class.func.label_get = (GenlistItemLabelGetFunc)_store_item_label_get;
559    _store_item_class.func.icon_get  = (GenlistItemIconGetFunc)_store_item_icon_get;
560    _store_item_class.func.state_get = NULL; // FIXME: support state gets later
561    _store_item_class.func.del       = (GenlistItemDelFunc)_store_item_del;
562    // TODO: END - move to elm_store_init()
563
564    EINA_MAGIC_SET(st, ELM_STORE_MAGIC);
565    st->cache_max = 128;
566    st->fetch_thread = EINA_TRUE;
567    st->type = 0;
568    return st;
569 }
570 #define elm_store_new(type) (type*)_elm_store_new(sizeof(type))
571
572 static void
573 _elm_store_filesystem_free(Elm_Store *store)
574 {
575    Elm_Store_Filesystem *st = (Elm_Store_Filesystem *)store;
576    eina_stringshare_del(st->dir);
577 }
578
579 static void
580 _elm_store_filesystem_item_free(Elm_Store_Item *item)
581 {
582    Elm_Store_Item_Filesystem *sti = (Elm_Store_Item_Filesystem *)item;
583    eina_stringshare_del(sti->path);
584 }
585
586 EAPI Elm_Store *
587 elm_store_filesystem_new(void)
588 {
589    Elm_Store_Filesystem *st = elm_store_new(Elm_Store_Filesystem);
590    EINA_SAFETY_ON_NULL_RETURN_VAL(st, NULL);
591
592    EINA_MAGIC_SET(st, ELM_STORE_FILESYSTEM_MAGIC);
593    st->base.free = _elm_store_filesystem_free;
594    st->base.item.free = _elm_store_filesystem_item_free;
595
596    return &st->base;
597 }
598
599 EAPI void
600 elm_store_free(Elm_Store *st)
601 {
602    void (*item_free)(Elm_Store_Item *);
603    if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return;
604    if (st->list_th)
605      {
606         ecore_thread_cancel(st->list_th);
607         st->list_th = NULL;
608      }
609
610    if (!st->type)
611      {
612         eina_list_free(st->realized);
613         item_free = st->item.free;
614         while (st->items)
615           {
616              Elm_Store_Item *sti = (Elm_Store_Item *)st->items;
617              if (sti->eval_job) ecore_job_del(sti->eval_job);
618              if (sti->fetch_th)
619                {
620                   ecore_thread_cancel(sti->fetch_th);
621                   sti->fetch_th = NULL;
622                }
623              if (item_free) item_free(sti);
624              if (sti->data)
625                {
626                   if (st->cb.unfetch.func)
627                     st->cb.unfetch.func(st->cb.unfetch.data, sti, NULL);
628                   sti->data = NULL;
629                }
630              LKD(sti->lock);
631              free(sti);
632           }
633         if (st->genlist)
634           {
635              evas_object_event_callback_del_full(st->genlist, EVAS_CALLBACK_DEL, _store_genlist_del, st);
636              evas_object_smart_callback_del(st->genlist, "realized", _store_genlist_item_realized);
637              evas_object_smart_callback_del(st->genlist, "unrealized", _store_genlist_item_unrealized);
638              elm_genlist_clear(st->genlist);
639              st->genlist = NULL;
640           }
641         if (st->free) st->free(st);
642      }
643    else
644      {
645         st->live = EINA_FALSE;
646         if (st->genlist)
647           {
648              evas_object_event_callback_del_full(st->genlist, EVAS_CALLBACK_DEL, _genlist_del, st);
649              evas_object_smart_callback_del(st->genlist, "realized", _item_realized);
650              evas_object_smart_callback_del(st->genlist, "unrealized", _item_unrealized);
651              elm_genlist_clear(st->genlist);
652              st->genlist = NULL;
653           }
654         Eina_List *l;
655         Eina_List *l_next;
656         Eina_List *header_list;
657
658         EINA_LIST_FOREACH_SAFE(st->header_items, l, l_next, header_list)
659           {
660              if (header_list)
661                {
662                   Eina_List *in_l;
663                   Eina_List *in_l_next;
664                   Elm_Store_Item *sti;
665                   EINA_LIST_FOREACH_SAFE(header_list, in_l, in_l_next, sti)
666                     {
667                        if(sti)
668                          {
669                             if (sti->fetch_th)
670                               {
671                                  ecore_thread_cancel(sti->fetch_th);
672                                  sti->fetch_th = NULL;
673                               }
674                             if (st->cb.item_free.func)
675                               {
676                                  st->cb.item_free.func(st->cb.item_free.data, sti->item_info);
677                               }
678                             if (sti->fetched)
679                               {
680                                  int index = elm_store_item_index_get(sti);
681                                  if (index != -1) _item_unfetch(st, index);
682                               }
683                             header_list = eina_list_remove(header_list, sti);
684                             LKD(sti->lock);
685                             free(sti);
686                          }
687                     }
688                   st->header_items = eina_list_remove(st->header_items, header_list);
689                   header_list = eina_list_free(header_list);
690                }
691           }
692         st->header_items = eina_list_free(st->header_items);
693      }
694    free(st);
695 }
696
697 EAPI void
698 elm_store_target_genlist_set(Elm_Store *st, Evas_Object *obj)
699 {
700    if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return;
701    if (st->genlist == obj) return;
702    if (st->genlist)
703      {
704         if (!st->type)
705           {
706              evas_object_event_callback_del_full(st->genlist, EVAS_CALLBACK_DEL, _store_genlist_del, st);
707              evas_object_smart_callback_del(st->genlist, "realized", _store_genlist_item_realized);
708              evas_object_smart_callback_del(st->genlist, "unrealized", _store_genlist_item_unrealized);
709           }
710         else
711           {
712              evas_object_event_callback_del_full(st->genlist, EVAS_CALLBACK_DEL, _genlist_del, st);
713              evas_object_smart_callback_del(st->genlist, "realized", _item_realized);
714              evas_object_smart_callback_del(st->genlist, "unrealized", _item_unrealized);
715           }
716         elm_genlist_clear(st->genlist);
717      }
718    st->genlist = obj;
719    if (!st->genlist) return;
720    if (!st->type)
721      {
722         evas_object_smart_callback_add(st->genlist, "realized", _store_genlist_item_realized, st);
723         evas_object_smart_callback_add(st->genlist, "unrealized", _store_genlist_item_unrealized, st);
724         evas_object_event_callback_add(st->genlist, EVAS_CALLBACK_DEL, _store_genlist_del, st);
725      }
726    else
727      {
728         evas_object_smart_callback_add(st->genlist, "realized", _item_realized, st);
729         evas_object_smart_callback_add(st->genlist, "unrealized", _item_unrealized, st);
730         evas_object_event_callback_add(st->genlist, EVAS_CALLBACK_DEL, _genlist_del, st);
731         st->block_count = elm_genlist_block_count_get(st->genlist);
732      }
733    elm_genlist_clear(st->genlist);
734 }
735
736 EAPI void
737 elm_store_filesystem_directory_set(Elm_Store *store, const char *dir)
738 {
739    Elm_Store_Filesystem *st = (Elm_Store_Filesystem *)store;
740    if (!EINA_MAGIC_CHECK(store, ELM_STORE_MAGIC)) return;
741    if (!EINA_MAGIC_CHECK(st, ELM_STORE_FILESYSTEM_MAGIC)) return;
742    if (store->list_th)
743      {
744         ecore_thread_cancel(store->list_th);
745         store->list_th = NULL;
746      }
747    if (!eina_stringshare_replace(&st->dir, dir)) return;
748    store->list_th = ecore_thread_feedback_run(_store_filesystem_list_do,
749                                               _store_filesystem_list_update,
750                                               _store_filesystem_list_end,
751                                               _store_filesystem_list_cancel,
752                                               st, EINA_TRUE);
753 }
754
755 EAPI const char *
756 elm_store_filesystem_directory_get(const Elm_Store *store)
757 {
758    const Elm_Store_Filesystem *st = (const Elm_Store_Filesystem *)store;
759    if (!EINA_MAGIC_CHECK(store, ELM_STORE_MAGIC)) return NULL;
760    if (!EINA_MAGIC_CHECK(st, ELM_STORE_FILESYSTEM_MAGIC)) return NULL;
761    return st->dir;
762 }
763
764 EAPI void
765 elm_store_cache_set(Elm_Store *st, int max)
766 {
767    if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return;
768    if (max < 0) max = 0;
769    st->cache_max = max;
770    if(!st->type) _store_cache_trim(st);
771 }
772
773 EAPI int
774 elm_store_cache_get(const Elm_Store *st)
775 {
776    if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return 0;
777    return st->cache_max;
778 }
779
780 EAPI void
781 elm_store_list_func_set(Elm_Store *st, Elm_Store_Item_List_Cb func, const void *data)
782 {
783    if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return;
784    st->cb.list.func = func;
785    st->cb.list.data = (void *)data;
786 }
787
788 EAPI void
789 elm_store_fetch_func_set(Elm_Store *st, Elm_Store_Item_Fetch_Cb func, const void *data)
790 {
791    if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return;
792    st->cb.fetch.func = func;
793    st->cb.fetch.data = (void *)data;
794 }
795
796 EAPI void
797 elm_store_fetch_thread_set(Elm_Store *st, Eina_Bool use_thread)
798 {
799    if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return;
800    st->fetch_thread = !!use_thread;
801 }
802
803 EAPI Eina_Bool
804 elm_store_fetch_thread_get(const Elm_Store *st)
805 {
806    if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return EINA_FALSE;
807    return st->fetch_thread;
808 }
809
810 EAPI void
811 elm_store_unfetch_func_set(Elm_Store *st, Elm_Store_Item_Unfetch_Cb func, const void *data)
812 {
813    if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return;
814    st->cb.unfetch.func = func;
815    st->cb.unfetch.data = (void *)data;
816 }
817
818 EAPI void
819 elm_store_sorted_set(Elm_Store *st, Eina_Bool sorted)
820 {
821    if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return;
822    st->sorted = sorted;
823 }
824
825 EAPI Eina_Bool
826 elm_store_sorted_get(const Elm_Store *st)
827 {
828    if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return EINA_FALSE;
829    return st->sorted;
830 }
831
832 EAPI void
833 elm_store_item_data_set(Elm_Store_Item *sti, void *data)
834 {
835    if (!EINA_MAGIC_CHECK(sti, ELM_STORE_ITEM_MAGIC)) return;
836    LKL(sti->lock);
837    sti->data = data;
838    LKU(sti->lock);
839 }
840
841 EAPI void *
842 elm_store_item_data_get(Elm_Store_Item *sti)
843 {
844    if (!EINA_MAGIC_CHECK(sti, ELM_STORE_ITEM_MAGIC)) return NULL;
845    void *d;
846    LKL(sti->lock);
847    d = sti->data;
848    LKU(sti->lock);
849    return d;
850 }
851
852 EAPI const Elm_Store *
853 elm_store_item_store_get(const Elm_Store_Item *sti)
854 {
855    if (!EINA_MAGIC_CHECK(sti, ELM_STORE_ITEM_MAGIC)) return NULL;
856    // dont need lock
857    return sti->store;
858 }
859
860 EAPI const Elm_Genlist_Item *
861 elm_store_item_genlist_item_get(const Elm_Store_Item *sti)
862 {
863    if (!EINA_MAGIC_CHECK(sti, ELM_STORE_ITEM_MAGIC)) return NULL;
864    // dont need lock
865    return sti->item;
866 }
867
868 EAPI const char *
869 elm_store_item_filesystem_path_get(const Elm_Store_Item *item)
870 {
871    Elm_Store_Item_Filesystem *sti = (Elm_Store_Item_Filesystem *)item;
872    Elm_Store_Filesystem *st;
873    if (!EINA_MAGIC_CHECK(item, ELM_STORE_ITEM_MAGIC)) return NULL;
874    if (!EINA_MAGIC_CHECK(item->store, ELM_STORE_MAGIC)) return NULL;
875    /* ensure we're dealing with filesystem item */
876    st = (Elm_Store_Filesystem *)item->store;
877    if (!EINA_MAGIC_CHECK(st, ELM_STORE_FILESYSTEM_MAGIC)) return NULL;
878    // dont need lock
879    return sti->path;
880 }
881
882 // TODO: BEGIN -DBsystem store
883
884 static Elm_Store *
885 _store_init(size_t size)
886 {
887    Elm_Store *st = calloc(1, size);
888    if (!st) return NULL;
889
890    eina_magic_string_set(ELM_STORE_MAGIC, "Elm_Store");
891    eina_magic_string_set(ELM_STORE_FILESYSTEM_MAGIC, "Elm_Store_Filesystem");
892    eina_magic_string_set(ELM_STORE_ITEM_MAGIC, "Elm_Store_Item");
893    eina_magic_string_set(ELM_STORE_DBSYSTEM_MAGIC, "Elm_Store_DBsystem");
894
895    _store_item_class.item_style = "default";
896    _store_item_class.func.label_get = (GenlistItemLabelGetFunc)_item_label_get;
897    _store_item_class.func.icon_get = (GenlistItemIconGetFunc)_item_icon_get;
898    _store_item_class.func.state_get = NULL;
899    _store_item_class.func.del = NULL;
900
901    EINA_MAGIC_SET(st, ELM_STORE_MAGIC);
902    st->cache_max = CACHE_COUNT;
903    st->start_fetch_index = 0;
904    st->end_fetch_index = 0;
905    st->live = EINA_TRUE;
906    st->multi_load = EINA_FALSE;
907    st->total_item_count = 0;
908    st->fetch_thread = EINA_FALSE;
909    st->type = 1;
910    return st;
911 }
912
913 #define _store_new(type) (type *)_store_init(sizeof(type))
914
915 static void
916 _genlist_del(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
917 {
918    EINA_SAFETY_ON_NULL_RETURN(data);
919    Elm_Store *st = data;
920    if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return;
921
922    elm_store_free(st);
923 }
924
925 static void
926 _store_fetch_do(void *data, Ecore_Thread *th __UNUSED__)
927 {
928    Elm_Store_Item *sti = data;
929
930    LKL(sti->lock);
931    if (!sti->fetched)
932      {
933         LKU(sti->lock);
934         sti->store->cb.fetch.func(sti->store->cb.fetch.data, sti, sti->item_info);
935         LKL(sti->lock);
936         sti->fetched = EINA_TRUE;
937      }
938    LKU(sti->lock);
939 }
940
941 static void
942 _store_fetch_end(void *data, Ecore_Thread *th)
943 {
944    Elm_Store_Item *sti = data;
945    LKL(sti->lock);
946    if (th == sti->fetch_th) sti->fetch_th = NULL;
947    LKU(sti->lock);
948 }
949
950 static void
951 _store_fetch_cancel(void *data, Ecore_Thread *th)
952 {
953    Elm_Store_Item *sti = data;
954    LKL(sti->lock);
955    if (th == sti->fetch_th) sti->fetch_th = NULL;
956    LKU(sti->lock);
957 }
958
959 static Elm_Store_Item *
960 _item_fetch(Elm_Store *st, int index)
961 {
962    EINA_SAFETY_ON_NULL_RETURN_VAL(st,NULL);
963    Elm_Store_Item *sti;
964
965    int in_index = 0;
966    Eina_List *l;
967    Eina_List *l_next;
968    Eina_List *header_list;
969    if (st->live)
970      {
971         EINA_LIST_FOREACH_SAFE(st->header_items, l, l_next, header_list)
972           {
973              if(header_list)
974                {
975                   if ((in_index + eina_list_count(header_list)) > index)
976                     {
977                        sti = eina_list_nth(header_list, index - in_index);
978                        if(sti)
979                          {
980                             if (st->cb.fetch.func)
981                               {
982                                  LKL(sti->lock);
983                                  if (st->fetch_thread)
984                                    {
985                                       if (!sti->fetch_th)
986                                         {
987                                            sti->fetch_th = ecore_thread_run(_store_fetch_do,
988                                                                             _store_fetch_end,
989                                                                             _store_fetch_cancel,
990                                                                             sti);
991                                         }
992                                    }
993                                  else
994                                    {
995                                       LKU(sti->lock);
996                                       st->cb.fetch.func(st->cb.fetch.data, sti, sti->item_info);
997                                       LKL(sti->lock);
998                                       sti->fetched = EINA_TRUE;
999                                    }
1000                                  LKU(sti->lock);
1001                               }
1002                             return sti;
1003                          }
1004                        else
1005                          {
1006                             return NULL;
1007                          }
1008                     }
1009                   else
1010                     {
1011                        in_index = in_index + eina_list_count(header_list);
1012                     }
1013                }
1014           }
1015      }
1016    return NULL;
1017 }
1018
1019 static Elm_Store_Item *
1020 _item_unfetch(Elm_Store *st, int index)
1021 {
1022    EINA_SAFETY_ON_NULL_RETURN_VAL(st,NULL);
1023
1024    int in_index = 0;
1025    Elm_Store_Item *sti;
1026    Eina_List *l;
1027    Eina_List *l_next;
1028    Eina_List *header_list;
1029
1030    if (st->live)
1031      {
1032         EINA_LIST_FOREACH_SAFE(st->header_items, l, l_next, header_list)
1033           {
1034              if(header_list)
1035                {
1036                   if ((in_index + eina_list_count(header_list)) > index)
1037                     {
1038                        sti = eina_list_nth(header_list, index - in_index);
1039                        if(sti)
1040                          {
1041                             if (st->cb.unfetch.func)
1042                               {
1043                                  LKL(sti->lock);
1044                                  if (sti->fetch_th)
1045                                    {
1046                                       LKU(sti->lock);
1047                                       ecore_thread_cancel(sti->fetch_th);
1048                                       sti->fetch_th = NULL;
1049                                       LKL(sti->lock);
1050                                    }
1051                                  LKU(sti->lock);
1052                                  st->cb.unfetch.func(st->cb.unfetch.data, sti, sti->item_info);
1053                                  LKL(sti->lock);
1054                                  sti->fetched = EINA_FALSE;
1055                                  LKU(sti->lock);
1056                               }
1057                             return sti;
1058                          }
1059                        else
1060                          {
1061                             return NULL;
1062                          }
1063                     }
1064                   else
1065                     {
1066                        in_index = in_index + eina_list_count(header_list);
1067                     }
1068                }
1069           }
1070      }
1071    return NULL;
1072 }
1073
1074 static const Elm_Store_Item_Mapping *
1075 _item_mapping_find(Elm_Store_Item *sti, const char *part)
1076 {
1077    if (!EINA_MAGIC_CHECK(sti, ELM_STORE_ITEM_MAGIC)) return NULL;
1078    const Elm_Store_Item_Mapping *m;
1079
1080    for (m = sti->item_info->mapping; m; m++)
1081      {
1082         if (m->type == ELM_STORE_ITEM_MAPPING_NONE) break;
1083         if (!strcmp(part, m->part)) return m;
1084      }
1085    return NULL;
1086 }
1087
1088 static void
1089 _item_realize(Elm_Store_Item *sti)
1090 {
1091    if (!EINA_MAGIC_CHECK(sti, ELM_STORE_ITEM_MAGIC)) return;
1092    Elm_Store *st = sti->store;
1093    if (sti->store->live)
1094      {
1095         int index = elm_store_item_index_get(sti);
1096
1097         if (index != -1)
1098           {
1099              if ((st->start_fetch_index <= index) && (index <= (st->start_fetch_index + st->cache_max)))
1100                {
1101                   if (sti->fetched)
1102                     {
1103                        _item_unfetch(st, index);
1104                     }
1105                   _item_fetch(st, index);
1106
1107                   if(st->end_fetch_index < index)
1108                     {
1109                        st->end_fetch_index = index;
1110                     }
1111                }
1112              else if (st->start_fetch_index > index)
1113                {
1114                   int diff = st->start_fetch_index - index;
1115                   int loop;
1116                   for (loop = 1; loop <= diff; loop++)
1117                     {
1118                        _item_unfetch(st, st->end_fetch_index);
1119                        st->end_fetch_index--;
1120                        _item_fetch(sti->store, (st->start_fetch_index - loop));
1121                     }
1122                   st->start_fetch_index = index;
1123                }
1124              else if (index > st->end_fetch_index)
1125                {
1126                   int diff = index - st->end_fetch_index;
1127                   int loop;
1128                   for (loop = 1; loop <= diff; loop++)
1129                     {
1130                        _item_unfetch(st, st->start_fetch_index);
1131                        st->start_fetch_index++;
1132                        _item_fetch(st, (st->end_fetch_index + loop));
1133                     }
1134                   st->end_fetch_index = index;
1135                }
1136           }
1137         else
1138           {
1139              return;
1140           }
1141      }
1142 }
1143
1144 static char *
1145 _item_label_get(void *data, Evas_Object *obj __UNUSED__, const char *part)
1146 {
1147    EINA_SAFETY_ON_NULL_RETURN_VAL(data, strdup(""));
1148    Elm_Store_Item *sti = data;
1149    EINA_SAFETY_ON_NULL_RETURN_VAL(sti,NULL);
1150
1151    if (sti->store->live)
1152      {
1153         if (sti->item)
1154           {
1155              if (!sti->data)
1156                {
1157                   _item_realize(sti);
1158                }
1159
1160              LKL(sti->lock);
1161              if (sti->data)
1162                {
1163                   const char *s = "";
1164                   const Elm_Store_Item_Mapping *m = _item_mapping_find(sti, part);
1165                   if (m)
1166                     {
1167                        switch (m->type)
1168                          {
1169                           case ELM_STORE_ITEM_MAPPING_LABEL:
1170                              s = *(char **)(((unsigned char *)sti->data) + m->offset);
1171                              break;
1172
1173                           case ELM_STORE_ITEM_MAPPING_CUSTOM:
1174                              if (m->details.custom.func)
1175                                s = m->details.custom.func(sti->data, sti, part);
1176                              break;
1177
1178                           default:
1179                              break;
1180                          }
1181                        if (s)
1182                          {
1183                             LKU(sti->lock);
1184                             return strdup(s);
1185                          }
1186                        else
1187                          {
1188                             LKU(sti->lock);
1189                             return NULL;
1190                          }
1191                     }
1192                }
1193              LKU(sti->lock);
1194           }
1195      }
1196    return NULL;
1197 }
1198
1199 static Evas_Object *
1200 _item_icon_get(void *data, Evas_Object *obj, const char *part)
1201 {
1202    EINA_SAFETY_ON_NULL_RETURN_VAL(data,NULL);
1203    Elm_Store_Item *sti = data;
1204    EINA_SAFETY_ON_NULL_RETURN_VAL(sti,NULL);
1205
1206    if (sti->store->live)
1207      {
1208         if (sti->item)
1209           {
1210              if (!sti->data)
1211                {
1212                   _item_realize(sti);
1213                }
1214
1215              LKL(sti->lock);
1216              if (sti->data)
1217                {
1218                   const Elm_Store_Item_Mapping *m = _item_mapping_find(sti, part);
1219                   if (m)
1220                     {
1221                        Evas_Object *ic = NULL;
1222                        const char *s = NULL;
1223
1224                        switch (m->type)
1225                          {
1226                           case ELM_STORE_ITEM_MAPPING_ICON:
1227                              ic = elm_icon_add(obj);
1228                              s = *(char **)(((unsigned char *)sti->data) + m->offset);
1229                              elm_icon_order_lookup_set(ic, m->details.icon.lookup_order);
1230                              evas_object_size_hint_aspect_set(ic,
1231                                                               EVAS_ASPECT_CONTROL_VERTICAL,
1232                                                               m->details.icon.w,
1233                                                               m->details.icon.h);
1234                              elm_icon_smooth_set(ic, m->details.icon.smooth);
1235                              elm_icon_no_scale_set(ic, m->details.icon.no_scale);
1236                              elm_icon_scale_set(ic,
1237                                                 m->details.icon.scale_up,
1238                                                 m->details.icon.scale_down);
1239
1240                              if (s)
1241                                {
1242                                   if (m->details.icon.standard_name)
1243                                     elm_icon_standard_set(ic, s);
1244                                   else
1245                                     elm_icon_file_set(ic, s, NULL);
1246                                }
1247                              break;
1248
1249                           case ELM_STORE_ITEM_MAPPING_PHOTO:
1250                              ic = elm_icon_add(obj);
1251                              s = *(char **)(((unsigned char *)sti->data) + m->offset);
1252                              elm_photo_size_set(ic, m->details.photo.size);
1253                              if (s)
1254                                elm_photo_file_set(ic, s);
1255                              break;
1256
1257                           case ELM_STORE_ITEM_MAPPING_CUSTOM:
1258                              if (m->details.custom.func)
1259                                ic = m->details.custom.func(sti->data, sti, part);
1260                              break;
1261
1262                           default:
1263                              break;
1264                          }
1265                        LKU(sti->lock);
1266                        return ic;
1267                     }
1268                }
1269              LKU(sti->lock);
1270           }
1271      }
1272    return NULL;
1273 }
1274
1275 static void
1276 _item_realized(void *data __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
1277 {
1278    /*   EINA_SAFETY_ON_NULL_RETURN(data);
1279         EINA_SAFETY_ON_NULL_RETURN(event_info);
1280         Elm_Store *st = data;
1281         Elm_Genlist_Item *gli = event_info;
1282         Elm_Store_Item *sti = elm_genlist_item_data_get(gli);
1283
1284         EINA_SAFETY_ON_NULL_RETURN(sti);
1285
1286         int index = elm_store_item_index_get(sti);
1287
1288         if (st->fetch_thread)
1289         {
1290         if ((st->start_fetch_index <= index) && (index <= st->end_fetch_index))
1291         {
1292         int middle_index = sti->store->start_fetch_index + (sti->store->cache_max) / 2;
1293
1294         if ((middle_index < index) && (sti->store->end_fetch_index < sti->store->total_item_count))
1295         {
1296         int diff = index - middle_index;
1297         int loop;
1298         for (loop = 0; loop < diff; loop++)
1299         {
1300         _item_unfetch(st, sti->store->start_fetch_index);
1301         sti->store->start_fetch_index++;
1302         _item_fetch(st, (sti->store->end_fetch_index + 1));
1303         sti->store->end_fetch_index++;
1304         }
1305         }
1306         else if ((middle_index > index) && (sti->store->start_fetch_index > 0))
1307         {
1308         int diff = st->current_top_index - index;
1309         int loop;
1310         for (loop = 0; loop < diff; loop++)
1311         {
1312         _item_unfetch(st, sti->store->end_fetch_index);
1313         sti->store->end_fetch_index--;
1314         _item_fetch(st, (sti->store->start_fetch_index - 1));
1315         sti->store->start_fetch_index--;
1316         }
1317         }
1318         else {
1319         if ((!sti->fetched))
1320         {
1321         _item_fetch(st, index);
1322         }
1323         }
1324         }
1325         }
1326
1327         if ((st->current_top_index > index))
1328         {
1329         st->current_top_index = index;
1330         }
1331         else if ((st->current_top_index + SCREEN_ITEM_COUNT) < index)
1332         {
1333         st->current_top_index = st->current_top_index + (index - (st->current_top_index + SCREEN_ITEM_COUNT));
1334         }
1335     */
1336    // TODO:
1337 }
1338
1339 static void
1340 _item_unrealized(void *data __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
1341 {
1342    /*   EINA_SAFETY_ON_NULL_RETURN(data);
1343         EINA_SAFETY_ON_NULL_RETURN(event_info);
1344         Elm_Genlist_Item *gli = event_info;
1345         Elm_Store_Item *sti = elm_genlist_item_data_get(gli);
1346         EINA_SAFETY_ON_NULL_RETURN(sti);*/
1347 }
1348
1349 static void
1350 _item_del(void *data, Evas_Object *obj __UNUSED__)
1351 {
1352    EINA_SAFETY_ON_NULL_RETURN(data);
1353    Elm_Store_Item *sti = data;
1354    EINA_SAFETY_ON_NULL_RETURN(sti);
1355    if (!EINA_MAGIC_CHECK(sti, ELM_STORE_ITEM_MAGIC)) return;
1356    elm_store_item_del(sti);
1357 }
1358
1359 static void
1360 _list_do(void *data, Ecore_Thread *th __UNUSED__)
1361 {
1362    EINA_SAFETY_ON_NULL_RETURN(data);
1363    Elm_Store *st = data;
1364    if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return;
1365
1366    if (st->multi_load == EINA_TRUE)
1367      {
1368         Elm_Store_Item_Info *item_info;
1369         Eina_Bool ok = EINA_FALSE;
1370         int loop;
1371         for (loop = 0; loop < st->item_count; loop++)
1372           {
1373              item_info = calloc(1, sizeof(Elm_Store_Item_Info));
1374              if (!item_info) return;
1375              item_info->index = loop;
1376
1377              if (st->cb.list.func)
1378                {
1379                   ok = st->cb.list.func(st->cb.list.data, item_info);
1380                }
1381              if (ok) ecore_thread_feedback(th, item_info);
1382              else free(item_info);
1383              if (ecore_thread_check(th)) break;
1384           }
1385      }
1386 }
1387
1388 static void
1389 _list_update(void *data, Ecore_Thread *th __UNUSED__, void *msg)
1390 {
1391    EINA_SAFETY_ON_NULL_RETURN(data);
1392    EINA_SAFETY_ON_NULL_RETURN(msg);
1393    Elm_Store *st = data;
1394    Elm_Store_Item_Info *info = msg;
1395
1396    elm_store_item_add(st, info);
1397 }
1398
1399 static void
1400 _list_end(void *data, Ecore_Thread *th)
1401 {
1402    EINA_SAFETY_ON_NULL_RETURN(data);
1403    EINA_SAFETY_ON_NULL_RETURN(th);
1404    Elm_Store *st = data;
1405
1406    if (th == st->list_th)
1407      {
1408         ecore_thread_cancel(st->list_th);
1409         st->list_th = NULL;
1410      }
1411 }
1412
1413 static void
1414 _list_cancel(void *data, Ecore_Thread *th)
1415 {
1416    EINA_SAFETY_ON_NULL_RETURN(data);
1417    EINA_SAFETY_ON_NULL_RETURN(th);
1418    Elm_Store *st = data;
1419
1420    if (th == st->list_th)
1421      {
1422         ecore_thread_cancel(st->list_th);
1423         st->list_th = NULL;
1424      }
1425 }
1426
1427 static void
1428 _item_select_cb(void *data __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info)
1429 {
1430    EINA_SAFETY_ON_NULL_RETURN(event_info);
1431
1432    const Elm_Genlist_Item *it = (Elm_Genlist_Item *)event_info;
1433    Elm_Store_Item *sti = elm_genlist_item_data_get(it);
1434    if (!EINA_MAGIC_CHECK(sti, ELM_STORE_ITEM_MAGIC)) return;
1435
1436    if (sti->store->cb.item_select.func)
1437      {
1438         sti->store->cb.item_select.func(sti->store->cb.item_select.data, sti);
1439      }
1440 }
1441
1442 static void
1443 _group_item_append(Elm_Store_Item *sti, Elm_Genlist_Item_Class *itc)
1444 {
1445    EINA_SAFETY_ON_NULL_RETURN(sti);
1446    if (!EINA_MAGIC_CHECK(sti, ELM_STORE_ITEM_MAGIC)) return;
1447    Elm_Store *st = sti->store;
1448    if (st->live)
1449      {
1450         if (st->header_items)
1451           {
1452              Eina_Bool header_add = EINA_TRUE;
1453              Eina_List *l;
1454              Eina_List *l_next;
1455              Eina_List *header_list;
1456
1457              EINA_LIST_FOREACH_SAFE(st->header_items, l, l_next, header_list)
1458                {
1459                   if(header_list)
1460                     {
1461                        Elm_Store_Item *item = eina_list_nth(header_list, 0);
1462                        if (item->item_info->group_index == sti->item_info->group_index)
1463                          {
1464                             header_add = EINA_FALSE;
1465                             break;
1466                          }
1467                     }
1468                }
1469              if (header_add)
1470                {
1471                   Eina_List *new_header_list = NULL;
1472                   sti->item_info->index = 0;
1473                   new_header_list = eina_list_append(new_header_list, sti);
1474                   st->total_item_count++;
1475
1476                   Eina_Bool last_header = EINA_TRUE;
1477                   Eina_List *l;
1478                   Eina_List *l_next;
1479                   Eina_List *header_list;
1480
1481                   EINA_LIST_FOREACH_SAFE(st->header_items, l, l_next, header_list)
1482                     {
1483                        if (header_list)
1484                          {
1485                             Elm_Store_Item *group_sti = eina_list_nth(header_list, 0);
1486                             if(group_sti->item_info->item_type == ELM_GENLIST_ITEM_GROUP)
1487                               {
1488                                  int sort;
1489                                  if (st->cb.item_sort.func)
1490                                    {
1491                                       sort = st->cb.item_sort.func(st->cb.item_sort.data, sti->item_info, group_sti->item_info);
1492
1493                                       if(sort == ELM_STORE_ITEM_SORT_LOW)
1494                                         {
1495                                            st->header_items = eina_list_prepend_relative(st->header_items, new_header_list, header_list);
1496                                            sti->item = elm_genlist_item_insert_before(st->genlist,
1497                                                                                       itc,
1498                                                                                       sti,
1499                                                                                       NULL,
1500                                                                                       group_sti->item,
1501                                                                                       ELM_GENLIST_ITEM_GROUP,
1502                                                                                       NULL,
1503                                                                                       NULL);
1504                                            last_header = EINA_FALSE;
1505                                            break;
1506                                         }
1507                                    }
1508                                  else
1509                                    {
1510                                       break;
1511                                    }
1512                               }
1513                          }
1514                     }
1515                   if (last_header)
1516                     {
1517                        st->header_items = eina_list_append(st->header_items, new_header_list);
1518                        sti->item = elm_genlist_item_append(st->genlist,
1519                                                            itc,
1520                                                            sti,
1521                                                            NULL,
1522                                                            ELM_GENLIST_ITEM_GROUP,
1523                                                            NULL,
1524                                                            NULL);
1525                     }
1526                   elm_store_item_update(sti);
1527                }
1528           }
1529         else
1530           {
1531              Eina_List *header_list = NULL;
1532              sti->item_info->index = 0;
1533              header_list = eina_list_append(header_list, sti);
1534              st->total_item_count++;
1535              st->header_items = eina_list_append(st->header_items, header_list);
1536              sti->item = elm_genlist_item_append(st->genlist,
1537                                                  itc,
1538                                                  sti,
1539                                                  NULL,
1540                                                  ELM_GENLIST_ITEM_GROUP,
1541                                                  NULL,
1542                                                  NULL);
1543              elm_store_item_update(sti);
1544           }
1545      }
1546 }
1547
1548 static void
1549 _normal_item_append(Elm_Store_Item *sti, Elm_Genlist_Item_Class *itc)
1550 {
1551    EINA_SAFETY_ON_NULL_RETURN(sti);
1552    if (!EINA_MAGIC_CHECK(sti, ELM_STORE_ITEM_MAGIC)) return;
1553    Elm_Store *st = sti->store;
1554    if (st->live)
1555      {
1556         if (sti->item_info->rec_item == EINA_TRUE)
1557           {
1558              if (sti->item_info->group_index == sti->item_info->pre_group_index)
1559                {
1560                   Eina_List *l;
1561                   Eina_List *l_next;
1562                   Eina_List *header_list;
1563
1564                   EINA_LIST_FOREACH_SAFE(st->header_items, l, l_next, header_list)
1565                     {
1566                        if(header_list)
1567                          {
1568                             Elm_Store_Item *header_item = eina_list_nth(header_list, 0);
1569                             if (header_item->item_info->group_index == sti->item_info->group_index)
1570                               {
1571                                  Eina_List *in_l;
1572                                  Eina_List *in_l_next;
1573                                  Elm_Store_Item *item;
1574
1575                                  EINA_LIST_FOREACH_SAFE(header_list, in_l, in_l_next, item)
1576                                    {
1577                                       if(item)
1578                                         {
1579                                            int sort;
1580                                            if (st->cb.item_sort.func)
1581                                              {
1582                                                 sort = st->cb.item_sort.func(st->cb.item_sort.data, sti->item_info, item->item_info);
1583
1584                                                 if(sort == ELM_STORE_ITEM_SORT_SAME)
1585                                                   {
1586                                                      elm_store_item_update(item);
1587                                                   }
1588                                              }
1589                                            else
1590                                              {
1591                                                 break;
1592                                              }
1593
1594                                         }
1595                                    }
1596                               }
1597                          }
1598                     }
1599                }
1600              else
1601                {
1602                   Eina_List *l;
1603                   Eina_List *l_next;
1604                   Eina_List *header_list;
1605
1606                   EINA_LIST_FOREACH_SAFE(st->header_items, l, l_next, header_list)
1607                     {
1608                        if(header_list)
1609                          {
1610                             Elm_Store_Item *header_item = eina_list_nth(header_list, 0);
1611                             if (header_item->item_info->group_index == sti->item_info->pre_group_index)
1612                               {
1613                                  Eina_Bool removed = EINA_FALSE;
1614                                  Eina_List *in_l;
1615                                  Eina_List *in_l_next;
1616                                  Elm_Store_Item *remove_item;
1617
1618                                  EINA_LIST_FOREACH_SAFE(header_list, in_l, in_l_next, remove_item)
1619                                    {
1620                                       if(remove_item)
1621                                         {
1622                                            if (removed == EINA_TRUE)
1623                                              {
1624                                                 remove_item->item_info->index--;
1625                                              }
1626                                            else
1627                                              {
1628                                                 int sort;
1629                                                 if (st->cb.item_sort.func)
1630                                                   {
1631                                                      sort = st->cb.item_sort.func(st->cb.item_sort.data, sti->item_info, remove_item->item_info);
1632
1633                                                      if(sort == ELM_STORE_ITEM_SORT_SAME)
1634                                                        {
1635                                                           if (st->cb.item_free.func)
1636                                                             {
1637                                                                st->cb.item_free.func(st->cb.item_free.data, remove_item->item_info);
1638                                                             }
1639                                                           if (remove_item->fetched)
1640                                                             {
1641                                                                int index = elm_store_item_index_get(remove_item);
1642                                                                if (index != -1)
1643                                                                  {
1644                                                                     _item_unfetch(st, index);
1645                                                                  }
1646                                                                else
1647                                                                  {
1648                                                                     return;
1649                                                                  }
1650                                                             }
1651                                                           header_list = eina_list_remove(header_list, remove_item);
1652                                                           st->total_item_count--;
1653                                                           LKD(remove_item->lock);
1654                                                           elm_genlist_item_del(remove_item->item);
1655                                                           free(remove_item);
1656
1657                                                           if (eina_list_count(header_list) == 0)
1658                                                             {
1659                                                                st->header_items = eina_list_remove(st->header_items, header_list);
1660                                                                header_list = eina_list_free(header_list);
1661                                                             }
1662                                                           else if(eina_list_count(header_list) == 1)
1663                                                             {
1664                                                                Elm_Store_Item *temp_sti = eina_list_nth(header_list, 0);
1665                                                                if (temp_sti->item_info->item_type == ELM_GENLIST_ITEM_GROUP)
1666                                                                  {
1667                                                                     if (st->cb.item_free.func)
1668                                                                       {
1669                                                                          st->cb.item_free.func(st->cb.item_free.data, temp_sti->item_info);
1670                                                                       }
1671                                                                     if (temp_sti->fetched)
1672                                                                       {
1673                                                                          int index = elm_store_item_index_get(temp_sti);
1674                                                                          if (index != -1)
1675                                                                            {
1676                                                                               _item_unfetch(st, index);
1677                                                                            }
1678                                                                          else
1679                                                                            {
1680                                                                               return;
1681                                                                            }
1682                                                                       }
1683                                                                     header_list = eina_list_remove(header_list, temp_sti);
1684                                                                     st->total_item_count--;
1685                                                                     LKD(temp_sti->lock);
1686                                                                     elm_genlist_item_del(temp_sti->item);
1687                                                                     free(temp_sti);
1688                                                                     st->header_items = eina_list_remove(st->header_items, header_list);
1689                                                                     header_list = eina_list_free(header_list);
1690                                                                  }
1691                                                             }
1692                                                           removed = EINA_TRUE;
1693                                                        }
1694                                                   }
1695                                                 else
1696                                                   {
1697                                                      break;
1698                                                   }
1699                                              }
1700                                         }
1701                                    }
1702                               }
1703                             else if (header_item->item_info->group_index == sti->item_info->group_index)
1704                               {
1705                                  Eina_Bool last_add = EINA_TRUE;
1706                                  Eina_List *in_l;
1707                                  Eina_List *in_l_next;
1708                                  Elm_Store_Item *comp_item;
1709
1710                                  EINA_LIST_FOREACH_SAFE(header_list, in_l, in_l_next, comp_item)
1711                                    {
1712                                       if(comp_item)
1713                                         {
1714                                            if(last_add == EINA_FALSE)
1715                                              {
1716                                                 comp_item->item_info->index++;
1717                                              }
1718                                            else
1719                                              {
1720                                                 int sort;
1721                                                 if (st->cb.item_sort.func)
1722                                                   {
1723                                                      sort = st->cb.item_sort.func(st->cb.item_sort.data, sti->item_info, comp_item->item_info);
1724
1725                                                      if(sort == ELM_STORE_ITEM_SORT_LOW)
1726                                                        {
1727                                                           sti->item_info->index = comp_item->item_info->index;
1728                                                           comp_item->item_info->index++;
1729                                                           header_list = eina_list_prepend_relative(header_list, sti, comp_item);
1730                                                           st->total_item_count++;
1731                                                           sti->item = elm_genlist_item_insert_before(st->genlist,
1732                                                                                                      itc,
1733                                                                                                      sti,
1734                                                                                                      header_item->item,
1735                                                                                                      comp_item->item,
1736                                                                                                      ELM_GENLIST_ITEM_NONE,
1737                                                                                                      (Evas_Smart_Cb)sti->store->cb.item_select.func,
1738                                                                                                      (void *)sti->store->cb.item_select.data);
1739                                                           elm_store_item_update(sti);
1740                                                           last_add = EINA_FALSE;
1741                                                        }
1742                                                   }
1743                                                 else
1744                                                   {
1745                                                      Elm_Store_Item *last_sti = eina_list_nth(header_list, eina_list_count(header_list) - 1);
1746                                                      sti->item_info->index = eina_list_count(header_list);
1747                                                      header_list = eina_list_append(header_list, sti);
1748                                                      st->total_item_count++;
1749                                                      sti->item = elm_genlist_item_insert_after(st->genlist,
1750                                                                                                itc,
1751                                                                                                sti,
1752                                                                                                header_item->item,
1753                                                                                                last_sti->item,
1754                                                                                                ELM_GENLIST_ITEM_NONE,
1755                                                                                                (Evas_Smart_Cb)sti->store->cb.item_select.func,
1756                                                                                                (void *)sti->store->cb.item_select.data);
1757                                                      elm_store_item_update(sti);
1758                                                      last_add = EINA_FALSE;
1759                                                      break;
1760                                                   }
1761                                              }
1762                                         }
1763                                    }
1764                                  if(last_add)
1765                                    {
1766                                       Elm_Store_Item *last_sti = eina_list_nth(header_list, eina_list_count(header_list) - 1);
1767                                       sti->item_info->index = eina_list_count(header_list);
1768                                       header_list = eina_list_append(header_list, sti);
1769                                       st->total_item_count++;
1770                                       sti->item = elm_genlist_item_insert_after(st->genlist,
1771                                                                                 itc,
1772                                                                                 sti,
1773                                                                                 header_item->item,
1774                                                                                 last_sti->item,
1775                                                                                 ELM_GENLIST_ITEM_NONE,
1776                                                                                 (Evas_Smart_Cb)sti->store->cb.item_select.func,
1777                                                                                 (void *)sti->store->cb.item_select.data);
1778                                       elm_store_item_update(sti);
1779                                    }
1780                               }
1781
1782                          }
1783                     }
1784                }
1785           }
1786         else
1787           {
1788              if (st->header_items)
1789                {
1790                   Eina_Bool normal_add = EINA_TRUE;
1791                   Eina_List *l;
1792                   Eina_List *l_next;
1793                   Eina_List *header_list;
1794
1795                   EINA_LIST_FOREACH_SAFE(st->header_items, l, l_next, header_list)
1796                     {
1797                        if (header_list)
1798                          {
1799                             Elm_Store_Item *header_item = eina_list_nth(header_list, 0);
1800
1801                             if(header_item)
1802                               {
1803                                  if (header_item->item_info->group_index == sti->item_info->group_index)
1804                                    {
1805                                       Eina_List *in_l;
1806                                       Eina_List *in_l_next;
1807                                       Elm_Store_Item *comp_item;
1808
1809                                       EINA_LIST_FOREACH_SAFE(header_list, in_l, in_l_next, comp_item)
1810                                         {
1811                                            if (comp_item )
1812                                              {
1813                                                 if(normal_add == EINA_FALSE)
1814                                                   {
1815                                                      comp_item->item_info->index++;
1816                                                   }
1817                                                 else
1818                                                   {
1819                                                      int sort;
1820                                                      if (st->cb.item_sort.func)
1821                                                        {
1822                                                           sort = st->cb.item_sort.func(st->cb.item_sort.data, sti->item_info, comp_item->item_info);
1823
1824                                                           if(sort == ELM_STORE_ITEM_SORT_LOW)
1825                                                             {
1826                                                                sti->item_info->index = comp_item->item_info->index;
1827                                                                comp_item->item_info->index++;
1828                                                                header_list = eina_list_prepend_relative(header_list, sti, comp_item);
1829                                                                st->total_item_count++;
1830                                                                sti->item = elm_genlist_item_insert_before(st->genlist,
1831                                                                                                           itc,
1832                                                                                                           sti,
1833                                                                                                           header_item->item,
1834                                                                                                           comp_item->item,
1835                                                                                                           ELM_GENLIST_ITEM_NONE,
1836                                                                                                           (Evas_Smart_Cb)sti->store->cb.item_select.func,
1837                                                                                                           (void *)sti->store->cb.item_select.data);
1838                                                                normal_add = EINA_FALSE;
1839                                                                elm_store_item_update(sti);
1840                                                             }
1841                                                        }
1842                                                      else
1843                                                        {
1844                                                           Elm_Store_Item *last_sti = eina_list_nth(header_list, eina_list_count(header_list) - 1);
1845                                                           sti->item_info->index = eina_list_count(header_list);
1846                                                           header_list = eina_list_append(header_list, sti);
1847                                                           st->total_item_count++;
1848                                                           sti->item = elm_genlist_item_insert_after(st->genlist,
1849                                                                                                     itc,
1850                                                                                                     sti,
1851                                                                                                     header_item->item,
1852                                                                                                     last_sti->item,
1853                                                                                                     ELM_GENLIST_ITEM_NONE,
1854                                                                                                     (Evas_Smart_Cb)sti->store->cb.item_select.func,
1855                                                                                                     (void *)sti->store->cb.item_select.data);
1856                                                           normal_add = EINA_FALSE;
1857                                                           elm_store_item_update(sti);
1858                                                           break;
1859                                                        }
1860                                                   }
1861                                              }
1862                                         }
1863                                       if(normal_add)
1864                                         {
1865                                            Elm_Store_Item *last_sti = eina_list_nth(header_list, eina_list_count(header_list) - 1);
1866                                            sti->item_info->index = eina_list_count(header_list);
1867                                            header_list = eina_list_append(header_list, sti);
1868                                            st->total_item_count++;
1869                                            sti->item = elm_genlist_item_insert_after(st->genlist,
1870                                                                                      itc,
1871                                                                                      sti,
1872                                                                                      header_item->item,
1873                                                                                      last_sti->item,
1874                                                                                      ELM_GENLIST_ITEM_NONE,
1875                                                                                      (Evas_Smart_Cb)sti->store->cb.item_select.func,
1876                                                                                      (void *)sti->store->cb.item_select.data);
1877                                            normal_add = EINA_FALSE;
1878                                            elm_store_item_update(sti);
1879                                         }
1880                                       if(normal_add == EINA_FALSE)
1881                                         {
1882                                            break;
1883                                         }
1884                                    }
1885                               }
1886                          }
1887                     }
1888                   if (normal_add)
1889                     {
1890                        Eina_List *new_header_list = NULL;
1891                        sti->item_info->index = 0;
1892                        new_header_list = eina_list_append(new_header_list, sti);
1893                        st->total_item_count++;
1894                        st->header_items = eina_list_append(st->header_items, new_header_list);
1895                        sti->item = elm_genlist_item_append(st->genlist,
1896                                                            itc,
1897                                                            sti,
1898                                                            NULL,
1899                                                            ELM_GENLIST_ITEM_NONE,
1900                                                            (Evas_Smart_Cb)sti->store->cb.item_select.func,
1901                                                            (void *)sti->store->cb.item_select.data);
1902                        elm_store_item_update(sti);
1903                     }
1904                }
1905              else
1906                {
1907                   if (st->live)
1908                     {
1909                        Eina_List *new_header_list = NULL;
1910                        sti->item_info->index = 0;
1911                        new_header_list = eina_list_append(new_header_list, sti);
1912                        st->total_item_count++;
1913                        st->header_items = eina_list_append(st->header_items, new_header_list);
1914                        sti->item = elm_genlist_item_append(st->genlist,
1915                                                            itc,
1916                                                            sti,
1917                                                            NULL,
1918                                                            ELM_GENLIST_ITEM_NONE,
1919                                                            (Evas_Smart_Cb)sti->store->cb.item_select.func,
1920                                                            (void *)sti->store->cb.item_select.data);
1921                        elm_store_item_update(sti);
1922                     }
1923                }
1924           }
1925      }
1926 }
1927
1928 static void
1929 _item_free(Elm_Store_Item *sti)
1930 {
1931    if (!EINA_MAGIC_CHECK(sti, ELM_STORE_ITEM_MAGIC)) return;
1932    elm_store_item_del(sti);
1933 }
1934
1935 static void
1936 _store_free(Elm_Store *st)
1937 {
1938    if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return;
1939
1940    Elm_Store_DBsystem *std = (Elm_Store_DBsystem *)st;
1941    eina_stringshare_del(std->p_db);
1942    elm_store_free(st);
1943 }
1944
1945 /**
1946  * Add a new dbsystem Store object
1947  *
1948  * @return The new object or NULL if it cannot be created
1949  *
1950  * @ingroup Store
1951  */
1952 EAPI Elm_Store *
1953 elm_store_dbsystem_new(void)
1954 {
1955    Elm_Store_DBsystem *std = _store_new(Elm_Store_DBsystem);
1956    EINA_SAFETY_ON_NULL_RETURN_VAL(std, NULL);
1957
1958    EINA_MAGIC_SET(std, ELM_STORE_DBSYSTEM_MAGIC);
1959    std->base.free = _store_free;
1960    std->base.item.free = _item_free;
1961    return &std->base;
1962 }
1963
1964 /**
1965  * Sets the item count of a store
1966  *
1967  * @param st The store object
1968  * @param count The item count of an store
1969  *
1970  * @ingroup Store
1971  */
1972 EAPI void
1973 elm_store_item_count_set(Elm_Store *st, int count)
1974 {
1975    EINA_SAFETY_ON_NULL_RETURN(st);
1976    if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return;
1977
1978    st->item_count = count;
1979    if (count > 0)
1980      {
1981         st->multi_load = EINA_TRUE;
1982      }
1983    else
1984      {
1985         st->multi_load = EINA_FALSE;
1986      }
1987 }
1988
1989
1990 /**
1991  * Set the select func that select the state of a list item whether true or false
1992  *
1993  * @param st The store object
1994  * @param func The select cb function of an store
1995  * @param data The new data pointer to set
1996  *
1997  * @ingroup Store
1998  */
1999 EAPI void
2000 elm_store_item_select_func_set(Elm_Store *st, Elm_Store_Item_Select_Cb func, const void *data)
2001 {
2002    EINA_SAFETY_ON_NULL_RETURN(st);
2003    if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return;
2004
2005    st->cb.item_select.func = func;
2006    st->cb.item_select.data = (void *)data;
2007 }
2008
2009 /**
2010  * Sets the sort func that sort the item with a next in the list
2011  *
2012  * @param st The store object
2013  * @param func The sort cb function of an store
2014  * @param data The new data pointer to set
2015  *
2016  * @ingroup Store
2017  */
2018 EAPI void
2019 elm_store_item_sort_func_set(Elm_Store *st, Elm_Store_Item_Sort_Cb func, const void *data)
2020 {
2021    EINA_SAFETY_ON_NULL_RETURN(st);
2022    if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return;
2023
2024    st->cb.item_sort.func = func;
2025    st->cb.item_sort.data = (void *)data;
2026 }
2027
2028 /**
2029  * Set the store item free func
2030  *
2031  * @param st The store object
2032  * @param func The free cb function of an store
2033  * @param data The new data pointer to set
2034  *
2035  * @ingroup Store
2036  */
2037 EAPI void
2038 elm_store_item_free_func_set(Elm_Store *st, Elm_Store_Item_Free_Cb func, const void *data)
2039 {
2040    EINA_SAFETY_ON_NULL_RETURN(st);
2041    if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return;
2042
2043    st->cb.item_free.func = func;
2044    st->cb.item_free.data = (void *)data;
2045 }
2046
2047 /**
2048  * Get the item index that included header items
2049  *
2050  * @param sti The store item object
2051  * @return The item index in genlist
2052  *
2053  * @ingroup Store
2054  */
2055 EAPI int
2056 elm_store_item_index_get(const Elm_Store_Item *sti)
2057 {
2058    EINA_SAFETY_ON_NULL_RETURN_VAL(sti, -1);
2059    if (!EINA_MAGIC_CHECK(sti, ELM_STORE_ITEM_MAGIC)) return -1;
2060    Elm_Store *st = sti->store;
2061
2062    if (st->live)
2063      {
2064         int index = 0;
2065         Eina_List *l;
2066         Eina_List *l_next;
2067         Eina_List *header_list;
2068
2069         EINA_LIST_FOREACH_SAFE(st->header_items, l, l_next, header_list)
2070           {
2071              if (header_list)
2072                {
2073                   Elm_Store_Item *temp_sti = eina_list_nth(header_list, 0);
2074                   if(temp_sti)
2075                     {
2076                        if (sti->item_info->group_index == temp_sti->item_info->group_index)
2077                          {
2078                             Eina_List *in_l;
2079                             Eina_List *in_l_next;
2080                             Elm_Store_Item *comp_item;
2081
2082                             EINA_LIST_FOREACH_SAFE(header_list, in_l, in_l_next, comp_item)
2083                               {
2084                                  if(comp_item)
2085                                    {
2086                                       if (comp_item->item_info->index == sti->item_info->index)
2087                                         {
2088                                            return index;
2089                                         }
2090                                       else
2091                                         {
2092                                            index++;
2093                                         }
2094                                    }
2095                               }
2096                          }
2097                        else
2098                          {
2099                             index = index + eina_list_count(header_list);
2100                          }
2101                     }
2102                }
2103           }
2104         return -1;
2105      }
2106    else
2107      {
2108         return -1;
2109      }
2110 }
2111
2112 /**
2113  * Get the item index of real data that don't included header items
2114  *
2115  * @param sti The store item object
2116  * @return The real item index
2117  *
2118  * @ingroup Store
2119  */
2120 EAPI int
2121 elm_store_item_data_index_get(const Elm_Store_Item *sti)
2122 {
2123    EINA_SAFETY_ON_NULL_RETURN_VAL(sti, -1);
2124    if (!EINA_MAGIC_CHECK(sti, ELM_STORE_ITEM_MAGIC)) return -1;
2125    Elm_Store *st = sti->store;
2126
2127    if (st->live)
2128      {
2129         if (sti->item_info->item_type == ELM_GENLIST_ITEM_NONE)
2130           {
2131              int index = 0;
2132              int group_item_count = 0;
2133              Eina_List *l;
2134              Eina_List *l_next;
2135              Eina_List *header_list;
2136
2137              EINA_LIST_FOREACH_SAFE(st->header_items, l, l_next, header_list)
2138                {
2139                   if (header_list)
2140                     {
2141                        Elm_Store_Item *temp_sti = eina_list_nth(header_list, 0);
2142
2143                        if(temp_sti->item_info->item_type == ELM_GENLIST_ITEM_GROUP)
2144                          {
2145                             group_item_count++;
2146                          }
2147
2148                        if (temp_sti->item_info->group_index == sti->item_info->group_index)
2149                          {
2150                             Eina_List *in_l;
2151                             Eina_List *in_l_next;
2152                             Elm_Store_Item *comp_item;
2153
2154                             EINA_LIST_FOREACH_SAFE(header_list, in_l, in_l_next, comp_item)
2155                               {
2156                                  if(comp_item)
2157                                    {
2158                                       if (comp_item->item_info->index == sti->item_info->index)
2159                                         {
2160                                            return (index - group_item_count);
2161                                         }
2162                                       else
2163                                         {
2164                                            index++;
2165                                         }
2166                                    }
2167                               }
2168                          }
2169                        else
2170                          {
2171                             index = index + eina_list_count(header_list);
2172                          }
2173                     }
2174                }
2175           }
2176         return -1;
2177      }
2178    else
2179      {
2180         return -1;
2181      }
2182 }
2183
2184 /**
2185  * Get the DB pointer of an item
2186  *
2187  * @param sti The store item object
2188  * @return The DB pointer of item
2189  *
2190  * @ingroup Store
2191  */
2192 EAPI void *
2193 elm_store_dbsystem_db_get(const Elm_Store_Item *sti)
2194 {
2195    if (!EINA_MAGIC_CHECK(sti, ELM_STORE_ITEM_MAGIC)) return NULL;
2196
2197    const Elm_Store_DBsystem *std = (const Elm_Store_DBsystem *)sti->store;
2198    if (!EINA_MAGIC_CHECK(sti->store, ELM_STORE_MAGIC)) return NULL;
2199    if (!EINA_MAGIC_CHECK(std, ELM_STORE_DBSYSTEM_MAGIC)) return NULL;
2200    return std->p_db;
2201 }
2202
2203 /**
2204  * Set the DB pointer of an item
2205  *
2206  * @param sti The store item object
2207  * @parm p_db The DB pointer of item
2208  *
2209  * @ingroup Store
2210  */
2211 EAPI void
2212 elm_store_dbsystem_db_set(Elm_Store *store, void *p_db)
2213 {
2214    Elm_Store_DBsystem *std = (Elm_Store_DBsystem *)store;
2215    if (!EINA_MAGIC_CHECK(store, ELM_STORE_MAGIC)) return;
2216    if (!EINA_MAGIC_CHECK(std, ELM_STORE_DBSYSTEM_MAGIC)) return;
2217
2218    std->p_db = p_db;
2219
2220    if (store->list_th)
2221      {
2222         ecore_thread_cancel(store->list_th);
2223         store->list_th = NULL;
2224      }
2225    store->list_th = ecore_thread_feedback_run(_list_do, _list_update, _list_end, _list_cancel, store, EINA_TRUE);
2226 }
2227
2228 /**
2229  * Append the item to the genlist
2230  *
2231  * @param st The store object
2232  * @param info The store item info dbsystem object
2233  * @return The item of store
2234  *
2235  * @ingroup Store
2236  */
2237 EAPI Elm_Store_Item *
2238 elm_store_item_add(Elm_Store *st, Elm_Store_Item_Info *info)
2239 {
2240    EINA_SAFETY_ON_NULL_RETURN_VAL(st, NULL);
2241    if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return NULL;
2242    EINA_SAFETY_ON_NULL_RETURN_VAL(info, NULL);
2243    Elm_Store_Item *sti;
2244    Elm_Genlist_Item_Class *itc;
2245
2246    sti = calloc(1, sizeof(Elm_Store_Item));
2247    if (!sti) return NULL;
2248
2249    LKI(sti->lock);
2250    EINA_MAGIC_SET(sti, ELM_STORE_ITEM_MAGIC);
2251
2252    sti->store = st;
2253    sti->item_info = info;
2254    sti->fetched = EINA_FALSE;
2255
2256    itc = info->item_class;
2257    if (!itc) itc = &_store_item_class;
2258    else
2259      {
2260         itc->func.label_get = (GenlistItemLabelGetFunc)_item_label_get;
2261         itc->func.icon_get = (GenlistItemIconGetFunc)_item_icon_get;
2262         itc->func.state_get = NULL;
2263         itc->func.del = NULL;
2264      }
2265
2266    if (st->live)
2267      {
2268         if (sti->item_info->item_type == ELM_GENLIST_ITEM_GROUP)
2269           {
2270              _group_item_append(sti, itc);
2271           }
2272         else
2273           {
2274              _normal_item_append(sti, itc);
2275           }
2276         return sti;
2277      }
2278    else
2279      {
2280         return NULL;
2281      }
2282 }
2283
2284 /**
2285  * Realize the visible items to the screen
2286  *
2287  * @param st The store object
2288  *
2289  * @ingroup Store
2290  */
2291 EAPI void
2292 elm_store_visible_items_update(Elm_Store *st)
2293 {
2294    EINA_SAFETY_ON_NULL_RETURN(st);
2295    if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return;
2296
2297    Eina_List *realized_list = elm_genlist_realized_items_get(st->genlist);
2298    if(realized_list)
2299      {
2300         Eina_List *l;
2301         Elm_Genlist_Item *it;
2302         EINA_LIST_FOREACH(realized_list, l, it)
2303           {
2304              if(it)
2305                {
2306                   Elm_Store_Item *realized_sti = elm_genlist_item_data_get(it);
2307                   int index = elm_store_item_index_get(realized_sti);
2308                   if (index != -1)
2309                     {
2310                        if(realized_sti->fetched)
2311                          {
2312                             _item_unfetch(st, index);
2313                          }
2314                        _item_fetch(st, index);
2315                        if (realized_sti->data) elm_genlist_item_update(realized_sti->item);
2316                     }
2317                   else
2318                     {
2319                        return;
2320                     }
2321                }
2322           }
2323      }
2324 }
2325
2326 /**
2327  * Realize the item to the screen
2328  *
2329  * @param sti The store item object
2330  *
2331  * @ingroup Store
2332  */
2333 EAPI void
2334 elm_store_item_update(Elm_Store_Item *sti)
2335 {
2336    EINA_SAFETY_ON_NULL_RETURN(sti);
2337    if (!EINA_MAGIC_CHECK(sti, ELM_STORE_ITEM_MAGIC)) return;
2338    Elm_Store *st = sti->store;
2339
2340    int index = elm_store_item_index_get(sti);
2341    if (index != -1)
2342      {
2343         if ((st->start_fetch_index <= index) && (index <= (st->start_fetch_index + st->cache_max)))
2344           {
2345              if (sti->fetched)
2346                {
2347                   _item_unfetch(st, index);
2348                }
2349              _item_fetch(st, index);
2350
2351              if(st->end_fetch_index < (st->total_item_count-1))
2352                {
2353                   if( (st->end_fetch_index - st->cache_max) == st->start_fetch_index)
2354                     {
2355                        _item_unfetch(st, (st->total_item_count-1));
2356                     }
2357                   else
2358                     {
2359                        st->end_fetch_index = (st->total_item_count-1);
2360                     }
2361                }
2362              if(sti->data) elm_genlist_item_update(sti->item);
2363           }
2364      }
2365    else
2366      {
2367         return;
2368      }
2369 }
2370
2371 /**
2372  * Delete the item of genlist
2373  *
2374  * @param sti The store item object
2375  *
2376  * @ingroup Store
2377  */
2378 EAPI void
2379 elm_store_item_del(Elm_Store_Item *sti)
2380 {
2381    EINA_SAFETY_ON_NULL_RETURN(sti);
2382    if (!EINA_MAGIC_CHECK(sti, ELM_STORE_ITEM_MAGIC)) return;
2383    Elm_Store *st = sti->store;
2384
2385    Eina_List *l;
2386    Eina_List*l_next;
2387    Eina_List *header_list;
2388
2389    if (st->live)
2390      {
2391         EINA_LIST_FOREACH_SAFE(st->header_items, l, l_next, header_list)
2392           {
2393              if (header_list)
2394                {
2395                   Elm_Store_Item *header_item = eina_list_nth(header_list, 0);
2396
2397                   if (header_item->item_info->group_index == sti->item_info->group_index)
2398                     {
2399                        Eina_Bool removed = EINA_FALSE;
2400                        Eina_List *in_l;
2401                        Eina_List *in_l_next;
2402                        Elm_Store_Item *remove_sti;
2403                        EINA_LIST_FOREACH_SAFE(header_list, in_l, in_l_next, remove_sti)
2404                          {
2405                             if(remove_sti)
2406                               {
2407                                  if (removed == EINA_TRUE)
2408                                    {
2409                                       remove_sti->item_info->index--;
2410                                    }
2411                                  else
2412                                    {
2413                                       if (remove_sti->item_info->index == sti->item_info->index)
2414                                         {
2415                                            if (st->cb.item_free.func)
2416                                              {
2417                                                 st->cb.item_free.func(st->cb.item_free.data, remove_sti->item_info);
2418                                              }
2419                                            if (remove_sti->fetched)
2420                                              {
2421                                                 int index = elm_store_item_index_get(remove_sti);
2422                                                 if (index != -1)
2423                                                   {
2424                                                      _item_unfetch(st, index);
2425                                                   }
2426                                                 else
2427                                                   {
2428                                                      return;
2429                                                   }
2430                                              }
2431                                            header_list = eina_list_remove(header_list, remove_sti);
2432                                            st->total_item_count--;
2433                                            LKD(remove_sti->lock);
2434                                            elm_genlist_item_del(remove_sti->item);
2435                                            free(remove_sti);
2436
2437                                            if (eina_list_count(header_list) == 0)
2438                                              {
2439                                                 st->header_items = eina_list_remove(st->header_items, header_list);
2440                                                 header_list = eina_list_free(header_list);
2441                                              }
2442                                            else if (eina_list_count(header_list) == 1)
2443                                              {
2444                                                 Elm_Store_Item *temp_sti = eina_list_nth(header_list, 0);
2445                                                 if (temp_sti->item_info->item_type == ELM_GENLIST_ITEM_GROUP)
2446                                                   {
2447                                                      if (st->cb.item_free.func)
2448                                                        {
2449                                                           st->cb.item_free.func(st->cb.item_free.data, temp_sti->item_info);
2450                                                        }
2451                                                      if (temp_sti->fetched)
2452                                                        {
2453                                                           int index = elm_store_item_index_get(temp_sti);
2454                                                           if (index != -1)
2455                                                             {
2456                                                                _item_unfetch(st, index);
2457                                                             }
2458                                                           else
2459                                                             {
2460                                                                return;
2461                                                             }
2462                                                        }
2463                                                      header_list = eina_list_remove(header_list, temp_sti);
2464                                                      st->total_item_count--;
2465                                                      LKD(temp_sti->lock);
2466                                                      elm_genlist_item_del(temp_sti->item);
2467                                                      free(temp_sti);
2468                                                      st->header_items = eina_list_remove(st->header_items, header_list);
2469                                                      header_list = eina_list_free(header_list);
2470                                                   }
2471                                              }
2472                                            removed = EINA_TRUE;
2473                                         }
2474                                    }
2475                               }
2476                          }
2477                     }
2478                }
2479           }
2480      }
2481 }
2482
2483 // TODO: END -DBsystem store
2484