[store] Fixed the header list free and thread cancel problem
[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 (st->fetch_thread && sti->fetch_th)
670                               {
671                                  ecore_thread_cancel(sti->fetch_th);
672                                  sti->fetch_th = NULL;
673                               }
674                             if (sti->fetched)
675                               {
676                                  int index = elm_store_item_index_get(sti);
677                                  if (index != -1) _item_unfetch(st, index);
678                               }
679                             if (st->cb.item_free.func)
680                               {
681                                  st->cb.item_free.func(st->cb.item_free.data, sti->item_info);
682                                  sti->item_info = NULL;
683                               }
684                             LKD(sti->lock);
685                          }
686                     }
687                   st->header_items = eina_list_remove(st->header_items, header_list);
688                   header_list = eina_list_free(header_list);
689                }
690           }
691         st->header_items = eina_list_free(st->header_items);
692      }
693    free(st);
694 }
695
696 EAPI void
697 elm_store_target_genlist_set(Elm_Store *st, Evas_Object *obj)
698 {
699    if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return;
700    if (st->genlist == obj) return;
701    if (st->genlist)
702      {
703         if (!st->type)
704           {
705              evas_object_event_callback_del_full(st->genlist, EVAS_CALLBACK_DEL, _store_genlist_del, st);
706              evas_object_smart_callback_del(st->genlist, "realized", _store_genlist_item_realized);
707              evas_object_smart_callback_del(st->genlist, "unrealized", _store_genlist_item_unrealized);
708           }
709         else
710           {
711              evas_object_event_callback_del_full(st->genlist, EVAS_CALLBACK_DEL, _genlist_del, st);
712              evas_object_smart_callback_del(st->genlist, "realized", _item_realized);
713              evas_object_smart_callback_del(st->genlist, "unrealized", _item_unrealized);
714           }
715         elm_genlist_clear(st->genlist);
716      }
717    st->genlist = obj;
718    if (!st->genlist) return;
719    if (!st->type)
720      {
721         evas_object_smart_callback_add(st->genlist, "realized", _store_genlist_item_realized, st);
722         evas_object_smart_callback_add(st->genlist, "unrealized", _store_genlist_item_unrealized, st);
723         evas_object_event_callback_add(st->genlist, EVAS_CALLBACK_DEL, _store_genlist_del, st);
724      }
725    else
726      {
727         evas_object_smart_callback_add(st->genlist, "realized", _item_realized, st);
728         evas_object_smart_callback_add(st->genlist, "unrealized", _item_unrealized, st);
729         evas_object_event_callback_add(st->genlist, EVAS_CALLBACK_DEL, _genlist_del, st);
730         st->block_count = elm_genlist_block_count_get(st->genlist);
731      }
732    elm_genlist_clear(st->genlist);
733 }
734
735 EAPI void
736 elm_store_filesystem_directory_set(Elm_Store *store, const char *dir)
737 {
738    Elm_Store_Filesystem *st = (Elm_Store_Filesystem *)store;
739    if (!EINA_MAGIC_CHECK(store, ELM_STORE_MAGIC)) return;
740    if (!EINA_MAGIC_CHECK(st, ELM_STORE_FILESYSTEM_MAGIC)) return;
741    if (store->list_th)
742      {
743         ecore_thread_cancel(store->list_th);
744         store->list_th = NULL;
745      }
746    if (!eina_stringshare_replace(&st->dir, dir)) return;
747    store->list_th = ecore_thread_feedback_run(_store_filesystem_list_do,
748                                               _store_filesystem_list_update,
749                                               _store_filesystem_list_end,
750                                               _store_filesystem_list_cancel,
751                                               st, EINA_TRUE);
752 }
753
754 EAPI const char *
755 elm_store_filesystem_directory_get(const Elm_Store *store)
756 {
757    const Elm_Store_Filesystem *st = (const Elm_Store_Filesystem *)store;
758    if (!EINA_MAGIC_CHECK(store, ELM_STORE_MAGIC)) return NULL;
759    if (!EINA_MAGIC_CHECK(st, ELM_STORE_FILESYSTEM_MAGIC)) return NULL;
760    return st->dir;
761 }
762
763 EAPI void
764 elm_store_cache_set(Elm_Store *st, int max)
765 {
766    if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return;
767    if (max < 0) max = 0;
768    st->cache_max = max;
769    if(!st->type) _store_cache_trim(st);
770 }
771
772 EAPI int
773 elm_store_cache_get(const Elm_Store *st)
774 {
775    if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return 0;
776    return st->cache_max;
777 }
778
779 EAPI void
780 elm_store_list_func_set(Elm_Store *st, Elm_Store_Item_List_Cb func, const void *data)
781 {
782    if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return;
783    st->cb.list.func = func;
784    st->cb.list.data = (void *)data;
785 }
786
787 EAPI void
788 elm_store_fetch_func_set(Elm_Store *st, Elm_Store_Item_Fetch_Cb func, const void *data)
789 {
790    if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return;
791    st->cb.fetch.func = func;
792    st->cb.fetch.data = (void *)data;
793 }
794
795 EAPI void
796 elm_store_fetch_thread_set(Elm_Store *st, Eina_Bool use_thread)
797 {
798    if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return;
799    st->fetch_thread = !!use_thread;
800 }
801
802 EAPI Eina_Bool
803 elm_store_fetch_thread_get(const Elm_Store *st)
804 {
805    if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return EINA_FALSE;
806    return st->fetch_thread;
807 }
808
809 EAPI void
810 elm_store_unfetch_func_set(Elm_Store *st, Elm_Store_Item_Unfetch_Cb func, const void *data)
811 {
812    if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return;
813    st->cb.unfetch.func = func;
814    st->cb.unfetch.data = (void *)data;
815 }
816
817 EAPI void
818 elm_store_sorted_set(Elm_Store *st, Eina_Bool sorted)
819 {
820    if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return;
821    st->sorted = sorted;
822 }
823
824 EAPI Eina_Bool
825 elm_store_sorted_get(const Elm_Store *st)
826 {
827    if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return EINA_FALSE;
828    return st->sorted;
829 }
830
831 EAPI void
832 elm_store_item_data_set(Elm_Store_Item *sti, void *data)
833 {
834    if (!EINA_MAGIC_CHECK(sti, ELM_STORE_ITEM_MAGIC)) return;
835    LKL(sti->lock);
836    sti->data = data;
837    LKU(sti->lock);
838 }
839
840 EAPI void *
841 elm_store_item_data_get(Elm_Store_Item *sti)
842 {
843    if (!EINA_MAGIC_CHECK(sti, ELM_STORE_ITEM_MAGIC)) return NULL;
844    void *d;
845    LKL(sti->lock);
846    d = sti->data;
847    LKU(sti->lock);
848    return d;
849 }
850
851 EAPI const Elm_Store *
852 elm_store_item_store_get(const Elm_Store_Item *sti)
853 {
854    if (!EINA_MAGIC_CHECK(sti, ELM_STORE_ITEM_MAGIC)) return NULL;
855    // dont need lock
856    return sti->store;
857 }
858
859 EAPI const Elm_Genlist_Item *
860 elm_store_item_genlist_item_get(const Elm_Store_Item *sti)
861 {
862    if (!EINA_MAGIC_CHECK(sti, ELM_STORE_ITEM_MAGIC)) return NULL;
863    // dont need lock
864    return sti->item;
865 }
866
867 EAPI const char *
868 elm_store_item_filesystem_path_get(const Elm_Store_Item *item)
869 {
870    Elm_Store_Item_Filesystem *sti = (Elm_Store_Item_Filesystem *)item;
871    Elm_Store_Filesystem *st;
872    if (!EINA_MAGIC_CHECK(item, ELM_STORE_ITEM_MAGIC)) return NULL;
873    if (!EINA_MAGIC_CHECK(item->store, ELM_STORE_MAGIC)) return NULL;
874    /* ensure we're dealing with filesystem item */
875    st = (Elm_Store_Filesystem *)item->store;
876    if (!EINA_MAGIC_CHECK(st, ELM_STORE_FILESYSTEM_MAGIC)) return NULL;
877    // dont need lock
878    return sti->path;
879 }
880
881 // TODO: BEGIN -DBsystem store
882
883 static Elm_Store *
884 _store_init(size_t size)
885 {
886    Elm_Store *st = calloc(1, size);
887    if (!st) return NULL;
888
889    eina_magic_string_set(ELM_STORE_MAGIC, "Elm_Store");
890    eina_magic_string_set(ELM_STORE_FILESYSTEM_MAGIC, "Elm_Store_Filesystem");
891    eina_magic_string_set(ELM_STORE_ITEM_MAGIC, "Elm_Store_Item");
892    eina_magic_string_set(ELM_STORE_DBSYSTEM_MAGIC, "Elm_Store_DBsystem");
893
894    _store_item_class.item_style = "default";
895    _store_item_class.func.label_get = (GenlistItemLabelGetFunc)_item_label_get;
896    _store_item_class.func.icon_get = (GenlistItemIconGetFunc)_item_icon_get;
897    _store_item_class.func.state_get = NULL;
898    _store_item_class.func.del = NULL;
899
900    EINA_MAGIC_SET(st, ELM_STORE_MAGIC);
901    st->cache_max = CACHE_COUNT;
902    st->start_fetch_index = 0;
903    st->end_fetch_index = 0;
904    st->live = EINA_TRUE;
905    st->multi_load = EINA_FALSE;
906    st->total_item_count = 0;
907    st->fetch_thread = EINA_FALSE;
908    st->type = 1;
909    return st;
910 }
911
912 #define _store_new(type) (type *)_store_init(sizeof(type))
913
914 static void
915 _genlist_del(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
916 {
917    EINA_SAFETY_ON_NULL_RETURN(data);
918    Elm_Store *st = data;
919    if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return;
920
921    elm_store_free(st);
922 }
923
924 static void
925 _store_fetch_do(void *data, Ecore_Thread *th __UNUSED__)
926 {
927    Elm_Store_Item *sti = data;
928
929    LKL(sti->lock);
930    if (!sti->fetched)
931      {
932         LKU(sti->lock);
933         sti->store->cb.fetch.func(sti->store->cb.fetch.data, sti, sti->item_info);
934         LKL(sti->lock);
935         sti->fetched = EINA_TRUE;
936      }
937    LKU(sti->lock);
938 }
939
940 static void
941 _store_fetch_end(void *data, Ecore_Thread *th)
942 {
943    Elm_Store_Item *sti = data;
944    LKL(sti->lock);
945    if(sti->data) elm_genlist_item_update(sti->item);
946    LKU(sti->lock);
947    if (th == sti->fetch_th) sti->fetch_th = NULL;
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    if(sti->data) elm_genlist_item_update(sti->item);
957    LKU(sti->lock);
958 }
959
960 static Elm_Store_Item *
961 _item_fetch(Elm_Store *st, int index)
962 {
963    EINA_SAFETY_ON_NULL_RETURN_VAL(st,NULL);
964    Elm_Store_Item *sti;
965
966    int in_index = 0;
967    Eina_List *l;
968    Eina_List *l_next;
969    Eina_List *header_list;
970    if (st->live)
971      {
972         EINA_LIST_FOREACH_SAFE(st->header_items, l, l_next, header_list)
973           {
974              if(header_list)
975                {
976                   if ((in_index + eina_list_count(header_list)) > index)
977                     {
978                        sti = eina_list_nth(header_list, index - in_index);
979                        if(sti)
980                          {
981                             if (st->cb.fetch.func)
982                               {
983                                  LKL(sti->lock);
984                                  if (st->fetch_thread)
985                                    {
986                                       if (!sti->fetch_th)
987                                         {
988                                            sti->fetch_th = ecore_thread_run(_store_fetch_do,
989                                                                             _store_fetch_end,
990                                                                             _store_fetch_cancel,
991                                                                             sti);
992                                         }
993                                    }
994                                  else
995                                    {
996                                       LKU(sti->lock);
997                                       st->cb.fetch.func(st->cb.fetch.data, sti, sti->item_info);
998                                       LKL(sti->lock);
999                                       sti->fetched = EINA_TRUE;
1000                                    }
1001                                  LKU(sti->lock);
1002                               }
1003                             return sti;
1004                          }
1005                        else
1006                          {
1007                             return NULL;
1008                          }
1009                     }
1010                   else
1011                     {
1012                        in_index = in_index + eina_list_count(header_list);
1013                     }
1014                }
1015           }
1016      }
1017    return NULL;
1018 }
1019
1020 static Elm_Store_Item *
1021 _item_unfetch(Elm_Store *st, int index)
1022 {
1023    EINA_SAFETY_ON_NULL_RETURN_VAL(st,NULL);
1024
1025    int in_index = 0;
1026    Elm_Store_Item *sti;
1027    Eina_List *l;
1028    Eina_List *l_next;
1029    Eina_List *header_list;
1030
1031    if (st->live)
1032      {
1033         EINA_LIST_FOREACH_SAFE(st->header_items, l, l_next, header_list)
1034           {
1035              if(header_list)
1036                {
1037                   if ((in_index + eina_list_count(header_list)) > index)
1038                     {
1039                        sti = eina_list_nth(header_list, index - in_index);
1040                        if(sti)
1041                          {
1042                             if (st->cb.unfetch.func)
1043                               {
1044                                  LKL(sti->lock);
1045                                  if (sti->fetch_th)
1046                                    {
1047                                       LKU(sti->lock);
1048                                       ecore_thread_cancel(sti->fetch_th);
1049                                       sti->fetch_th = NULL;
1050                                       LKL(sti->lock);
1051                                    }
1052                                  LKU(sti->lock);
1053                                  st->cb.unfetch.func(st->cb.unfetch.data, sti, sti->item_info);
1054                                  LKL(sti->lock);
1055                                  sti->fetched = EINA_FALSE;
1056                                  LKU(sti->lock);
1057                               }
1058                             return sti;
1059                          }
1060                        else
1061                          {
1062                             return NULL;
1063                          }
1064                     }
1065                   else
1066                     {
1067                        in_index = in_index + eina_list_count(header_list);
1068                     }
1069                }
1070           }
1071      }
1072    return NULL;
1073 }
1074
1075 static const Elm_Store_Item_Mapping *
1076 _item_mapping_find(Elm_Store_Item *sti, const char *part)
1077 {
1078    if (!EINA_MAGIC_CHECK(sti, ELM_STORE_ITEM_MAGIC)) return NULL;
1079    const Elm_Store_Item_Mapping *m;
1080
1081    if(!sti->item_info)
1082      {
1083         return NULL;
1084      }
1085
1086    for (m = sti->item_info->mapping; m; m++)
1087      {
1088         if (m->type == ELM_STORE_ITEM_MAPPING_NONE) break;
1089         if (!strcmp(part, m->part)) return m;
1090      }
1091    return NULL;
1092 }
1093
1094 static void
1095 _item_realize(Elm_Store_Item *sti)
1096 {
1097    if (!EINA_MAGIC_CHECK(sti, ELM_STORE_ITEM_MAGIC)) return;
1098    Elm_Store *st = sti->store;
1099    if (sti->store->live)
1100      {
1101         int index = elm_store_item_index_get(sti);
1102
1103         if (index != -1)
1104           {
1105              if ((st->start_fetch_index <= index) && (index <= (st->start_fetch_index + st->cache_max)))
1106                {
1107                   if (sti->fetched)
1108                     {
1109                        _item_unfetch(st, index);
1110                     }
1111                   _item_fetch(st, index);
1112
1113                   if(st->end_fetch_index < index)
1114                     {
1115                        st->end_fetch_index = index;
1116                     }
1117                }
1118              else if (st->start_fetch_index > index)
1119                {
1120                   int diff = st->start_fetch_index - index;
1121                   int loop;
1122                   for (loop = 1; loop <= diff; loop++)
1123                     {
1124                        _item_unfetch(st, st->end_fetch_index);
1125                        st->end_fetch_index--;
1126                        _item_fetch(sti->store, (st->start_fetch_index - loop));
1127                     }
1128                   st->start_fetch_index = index;
1129                }
1130              else if (index > st->end_fetch_index)
1131                {
1132                   int diff = index - st->end_fetch_index;
1133                   int loop;
1134                   for (loop = 1; loop <= diff; loop++)
1135                     {
1136                        _item_unfetch(st, st->start_fetch_index);
1137                        st->start_fetch_index++;
1138                        _item_fetch(st, (st->end_fetch_index + loop));
1139                     }
1140                   st->end_fetch_index = index;
1141                }
1142           }
1143         else
1144           {
1145              return;
1146           }
1147      }
1148 }
1149
1150 static char *
1151 _item_label_get(void *data, Evas_Object *obj __UNUSED__, const char *part)
1152 {
1153    EINA_SAFETY_ON_NULL_RETURN_VAL(data, strdup(""));
1154    Elm_Store_Item *sti = data;
1155    EINA_SAFETY_ON_NULL_RETURN_VAL(sti,NULL);
1156
1157    if (sti->store->live)
1158      {
1159         if (sti->item)
1160           {
1161              if (!sti->data)
1162                {
1163                   _item_realize(sti);
1164                }
1165
1166              LKL(sti->lock);
1167              if (sti->data)
1168                {
1169                   const char *s = "";
1170                   const Elm_Store_Item_Mapping *m = _item_mapping_find(sti, part);
1171                   if (m)
1172                     {
1173                        switch (m->type)
1174                          {
1175                           case ELM_STORE_ITEM_MAPPING_LABEL:
1176                              s = *(char **)(((unsigned char *)sti->data) + m->offset);
1177                              break;
1178
1179                           case ELM_STORE_ITEM_MAPPING_CUSTOM:
1180                              if (m->details.custom.func)
1181                                s = m->details.custom.func(sti->data, sti, part);
1182                              break;
1183
1184                           default:
1185                              break;
1186                          }
1187                        if (s)
1188                          {
1189                             LKU(sti->lock);
1190                             return strdup(s);
1191                          }
1192                        else
1193                          {
1194                             LKU(sti->lock);
1195                             return NULL;
1196                          }
1197                     }
1198                }
1199              LKU(sti->lock);
1200           }
1201      }
1202    return NULL;
1203 }
1204
1205 static Evas_Object *
1206 _item_icon_get(void *data, Evas_Object *obj, const char *part)
1207 {
1208    EINA_SAFETY_ON_NULL_RETURN_VAL(data,NULL);
1209    Elm_Store_Item *sti = data;
1210    EINA_SAFETY_ON_NULL_RETURN_VAL(sti,NULL);
1211
1212    if (sti->store->live)
1213      {
1214         if (sti->item)
1215           {
1216              if (!sti->data)
1217                {
1218                   _item_realize(sti);
1219                }
1220
1221              LKL(sti->lock);
1222              if (sti->data)
1223                {
1224                   const Elm_Store_Item_Mapping *m = _item_mapping_find(sti, part);
1225                   if (m)
1226                     {
1227                        Evas_Object *ic = NULL;
1228                        const char *s = NULL;
1229
1230                        switch (m->type)
1231                          {
1232                           case ELM_STORE_ITEM_MAPPING_ICON:
1233                              ic = elm_icon_add(obj);
1234                              s = *(char **)(((unsigned char *)sti->data) + m->offset);
1235                              elm_icon_order_lookup_set(ic, m->details.icon.lookup_order);
1236                              evas_object_size_hint_aspect_set(ic,
1237                                                               EVAS_ASPECT_CONTROL_VERTICAL,
1238                                                               m->details.icon.w,
1239                                                               m->details.icon.h);
1240                              elm_icon_smooth_set(ic, m->details.icon.smooth);
1241                              elm_icon_no_scale_set(ic, m->details.icon.no_scale);
1242                              elm_icon_scale_set(ic,
1243                                                 m->details.icon.scale_up,
1244                                                 m->details.icon.scale_down);
1245
1246                              if (s)
1247                                {
1248                                   if (m->details.icon.standard_name)
1249                                     elm_icon_standard_set(ic, s);
1250                                   else
1251                                     elm_icon_file_set(ic, s, NULL);
1252                                }
1253                              break;
1254
1255                           case ELM_STORE_ITEM_MAPPING_PHOTO:
1256                              ic = elm_icon_add(obj);
1257                              s = *(char **)(((unsigned char *)sti->data) + m->offset);
1258                              elm_photo_size_set(ic, m->details.photo.size);
1259                              if (s)
1260                                elm_photo_file_set(ic, s);
1261                              break;
1262
1263                           case ELM_STORE_ITEM_MAPPING_CUSTOM:
1264                              if (m->details.custom.func)
1265                                ic = m->details.custom.func(sti->data, sti, part);
1266                              break;
1267
1268                           default:
1269                              break;
1270                          }
1271                        LKU(sti->lock);
1272                        return ic;
1273                     }
1274                }
1275              LKU(sti->lock);
1276           }
1277      }
1278    return NULL;
1279 }
1280
1281 static void
1282 _item_realized(void *data __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
1283 {
1284    /*   EINA_SAFETY_ON_NULL_RETURN(data);
1285         EINA_SAFETY_ON_NULL_RETURN(event_info);
1286         Elm_Store *st = data;
1287         Elm_Genlist_Item *gli = event_info;
1288         Elm_Store_Item *sti = elm_genlist_item_data_get(gli);
1289
1290         EINA_SAFETY_ON_NULL_RETURN(sti);
1291
1292         int index = elm_store_item_index_get(sti);
1293
1294         if (st->fetch_thread)
1295         {
1296         if ((st->start_fetch_index <= index) && (index <= st->end_fetch_index))
1297         {
1298         int middle_index = sti->store->start_fetch_index + (sti->store->cache_max) / 2;
1299
1300         if ((middle_index < index) && (sti->store->end_fetch_index < sti->store->total_item_count))
1301         {
1302         int diff = index - middle_index;
1303         int loop;
1304         for (loop = 0; loop < diff; loop++)
1305         {
1306         _item_unfetch(st, sti->store->start_fetch_index);
1307         sti->store->start_fetch_index++;
1308         _item_fetch(st, (sti->store->end_fetch_index + 1));
1309         sti->store->end_fetch_index++;
1310         }
1311         }
1312         else if ((middle_index > index) && (sti->store->start_fetch_index > 0))
1313         {
1314         int diff = st->current_top_index - index;
1315         int loop;
1316         for (loop = 0; loop < diff; loop++)
1317         {
1318         _item_unfetch(st, sti->store->end_fetch_index);
1319         sti->store->end_fetch_index--;
1320         _item_fetch(st, (sti->store->start_fetch_index - 1));
1321         sti->store->start_fetch_index--;
1322         }
1323         }
1324         else {
1325         if ((!sti->fetched))
1326         {
1327         _item_fetch(st, index);
1328         }
1329         }
1330         }
1331         }
1332
1333         if ((st->current_top_index > index))
1334         {
1335         st->current_top_index = index;
1336         }
1337         else if ((st->current_top_index + SCREEN_ITEM_COUNT) < index)
1338         {
1339         st->current_top_index = st->current_top_index + (index - (st->current_top_index + SCREEN_ITEM_COUNT));
1340         }
1341     */
1342    // TODO:
1343 }
1344
1345 static void
1346 _item_unrealized(void *data __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
1347 {
1348    /*   EINA_SAFETY_ON_NULL_RETURN(data);
1349         EINA_SAFETY_ON_NULL_RETURN(event_info);
1350         Elm_Genlist_Item *gli = event_info;
1351         Elm_Store_Item *sti = elm_genlist_item_data_get(gli);
1352         EINA_SAFETY_ON_NULL_RETURN(sti);*/
1353 }
1354
1355 static void
1356 _item_del(void *data, Evas_Object *obj __UNUSED__)
1357 {
1358    EINA_SAFETY_ON_NULL_RETURN(data);
1359    Elm_Store_Item *sti = data;
1360    EINA_SAFETY_ON_NULL_RETURN(sti);
1361    if (!EINA_MAGIC_CHECK(sti, ELM_STORE_ITEM_MAGIC)) return;
1362    elm_store_item_del(sti);
1363 }
1364
1365 static void
1366 _list_do(void *data, Ecore_Thread *th __UNUSED__)
1367 {
1368    EINA_SAFETY_ON_NULL_RETURN(data);
1369    Elm_Store *st = data;
1370    if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return;
1371
1372    if (st->multi_load == EINA_TRUE)
1373      {
1374         Elm_Store_Item_Info *item_info;
1375         Eina_Bool ok = EINA_FALSE;
1376         int loop;
1377         for (loop = 0; loop < st->item_count; loop++)
1378           {
1379              item_info = calloc(1, sizeof(Elm_Store_Item_Info));
1380              if (!item_info) return;
1381              item_info->index = loop;
1382
1383              if (st->cb.list.func)
1384                {
1385                   ok = st->cb.list.func(st->cb.list.data, item_info);
1386                }
1387              if (ok) ecore_thread_feedback(th, item_info);
1388              else free(item_info);
1389              if (ecore_thread_check(th)) break;
1390           }
1391      }
1392 }
1393
1394 static void
1395 _list_update(void *data, Ecore_Thread *th __UNUSED__, void *msg)
1396 {
1397    EINA_SAFETY_ON_NULL_RETURN(data);
1398    EINA_SAFETY_ON_NULL_RETURN(msg);
1399    Elm_Store *st = data;
1400    Elm_Store_Item_Info *info = msg;
1401
1402    elm_store_item_add(st, info);
1403 }
1404
1405 static void
1406 _list_end(void *data, Ecore_Thread *th)
1407 {
1408    Elm_Store *st = data;
1409    if (th == st->list_th) st->list_th = NULL;
1410 }
1411
1412 static void
1413 _list_cancel(void *data, Ecore_Thread *th)
1414 {
1415    Elm_Store *st = data;
1416    if (th == st->list_th) st->list_th = NULL;
1417 }
1418
1419 static void
1420 _item_select_cb(void *data __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info)
1421 {
1422    EINA_SAFETY_ON_NULL_RETURN(event_info);
1423
1424    const Elm_Genlist_Item *it = (Elm_Genlist_Item *)event_info;
1425    Elm_Store_Item *sti = elm_genlist_item_data_get(it);
1426    if (!EINA_MAGIC_CHECK(sti, ELM_STORE_ITEM_MAGIC)) return;
1427
1428    if (sti->store->cb.item_select.func)
1429      {
1430         sti->store->cb.item_select.func(sti->store->cb.item_select.data, sti);
1431      }
1432 }
1433
1434 static void
1435 _group_item_append(Elm_Store_Item *sti, Elm_Genlist_Item_Class *itc)
1436 {
1437    EINA_SAFETY_ON_NULL_RETURN(sti);
1438    if (!EINA_MAGIC_CHECK(sti, ELM_STORE_ITEM_MAGIC)) return;
1439    Elm_Store *st = sti->store;
1440    if (st->live)
1441      {
1442         if (st->header_items)
1443           {
1444              Eina_Bool header_add = EINA_TRUE;
1445              Eina_List *l;
1446              Eina_List *l_next;
1447              Eina_List *header_list;
1448
1449              EINA_LIST_FOREACH_SAFE(st->header_items, l, l_next, header_list)
1450                {
1451                   if(header_list)
1452                     {
1453                        Elm_Store_Item *item = eina_list_nth(header_list, 0);
1454                        if(item && item->item_info)
1455                          {
1456                             if (item->item_info->group_index == sti->item_info->group_index)
1457                               {
1458                                  header_add = EINA_FALSE;
1459                                  break;
1460                               }
1461                          }
1462                     }
1463                }
1464              if (header_add)
1465                {
1466                   Eina_List *new_header_list = NULL;
1467                   sti->item_info->index = 0;
1468                   new_header_list = eina_list_append(new_header_list, sti);
1469                   st->total_item_count++;
1470
1471                   Eina_Bool last_header = EINA_TRUE;
1472                   Eina_List *l;
1473                   Eina_List *l_next;
1474                   Eina_List *header_list;
1475
1476                   EINA_LIST_FOREACH_SAFE(st->header_items, l, l_next, header_list)
1477                     {
1478                        if (header_list)
1479                          {
1480                             Elm_Store_Item *group_sti = eina_list_nth(header_list, 0);
1481                             if(group_sti && group_sti->item_info)
1482                               {
1483                                  if(group_sti->item_info->item_type == ELM_GENLIST_ITEM_GROUP)
1484                                    {
1485                                       int sort;
1486                                       if (st->cb.item_sort.func)
1487                                         {
1488                                            sort = st->cb.item_sort.func(st->cb.item_sort.data, sti->item_info, group_sti->item_info);
1489
1490                                            if(sort == ELM_STORE_ITEM_SORT_LOW)
1491                                              {
1492                                                 st->header_items = eina_list_prepend_relative(st->header_items, new_header_list, header_list);
1493                                                 sti->item = elm_genlist_item_insert_before(st->genlist,
1494                                                                                            itc,
1495                                                                                            sti,
1496                                                                                            NULL,
1497                                                                                            group_sti->item,
1498                                                                                            ELM_GENLIST_ITEM_GROUP,
1499                                                                                            NULL,
1500                                                                                            NULL);
1501                                                 last_header = EINA_FALSE;
1502                                                 break;
1503                                              }
1504                                         }
1505                                       else
1506                                         {
1507                                            break;
1508                                         }
1509                                    }
1510                               }
1511                          }
1512                     }
1513                   if (last_header)
1514                     {
1515                        st->header_items = eina_list_append(st->header_items, new_header_list);
1516                        sti->item = elm_genlist_item_append(st->genlist,
1517                                                            itc,
1518                                                            sti,
1519                                                            NULL,
1520                                                            ELM_GENLIST_ITEM_GROUP,
1521                                                            NULL,
1522                                                            NULL);
1523                     }
1524                   elm_store_item_update(sti);
1525                }
1526           }
1527         else
1528           {
1529              Eina_List *header_list = NULL;
1530              sti->item_info->index = 0;
1531              header_list = eina_list_append(header_list, sti);
1532              st->total_item_count++;
1533              st->header_items = eina_list_append(st->header_items, header_list);
1534              sti->item = elm_genlist_item_append(st->genlist,
1535                                                  itc,
1536                                                  sti,
1537                                                  NULL,
1538                                                  ELM_GENLIST_ITEM_GROUP,
1539                                                  NULL,
1540                                                  NULL);
1541              elm_store_item_update(sti);
1542           }
1543      }
1544 }
1545
1546 static void
1547 _normal_item_append(Elm_Store_Item *sti, Elm_Genlist_Item_Class *itc)
1548 {
1549    EINA_SAFETY_ON_NULL_RETURN(sti);
1550    if (!EINA_MAGIC_CHECK(sti, ELM_STORE_ITEM_MAGIC)) return;
1551    Elm_Store *st = sti->store;
1552    if (st->live)
1553      {
1554         if (sti->item_info->rec_item == EINA_TRUE)
1555           {
1556              if (sti->item_info->group_index == sti->item_info->pre_group_index)
1557                {
1558                   Eina_List *l;
1559                   Eina_List *l_next;
1560                   Eina_List *header_list;
1561
1562                   EINA_LIST_FOREACH_SAFE(st->header_items, l, l_next, header_list)
1563                     {
1564                        if(header_list)
1565                          {
1566                             Elm_Store_Item *header_item = eina_list_nth(header_list, 0);
1567                             if(header_item && header_item->item_info)
1568                               {
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                }
1601              else
1602                {
1603                   Eina_List *l;
1604                   Eina_List *l_next;
1605                   Eina_List *header_list;
1606
1607                   EINA_LIST_FOREACH_SAFE(st->header_items, l, l_next, header_list)
1608                     {
1609                        if(header_list)
1610                          {
1611                             Elm_Store_Item *header_item = eina_list_nth(header_list, 0);
1612                             if(header_item && header_item->item_info)
1613                               {
1614                                  if (header_item->item_info->group_index == sti->item_info->pre_group_index)
1615                                    {
1616                                       Eina_Bool removed = EINA_FALSE;
1617                                       Eina_List *in_l;
1618                                       Eina_List *in_l_next;
1619                                       Elm_Store_Item *remove_item;
1620
1621                                       EINA_LIST_FOREACH_SAFE(header_list, in_l, in_l_next, remove_item)
1622                                         {
1623                                            if(remove_item)
1624                                              {
1625                                                 if (removed == EINA_TRUE)
1626                                                   {
1627                                                      remove_item->item_info->index--;
1628                                                   }
1629                                                 else
1630                                                   {
1631                                                      int sort;
1632                                                      if (st->cb.item_sort.func)
1633                                                        {
1634                                                           sort = st->cb.item_sort.func(st->cb.item_sort.data, sti->item_info, remove_item->item_info);
1635
1636                                                           if(sort == ELM_STORE_ITEM_SORT_SAME)
1637                                                             {
1638                                                                if (remove_item->fetched)
1639                                                                  {
1640                                                                     int index = elm_store_item_index_get(remove_item);
1641                                                                     if (index != -1)
1642                                                                       {
1643                                                                          _item_unfetch(st, index);
1644                                                                       }
1645                                                                     else
1646                                                                       {
1647                                                                          return;
1648                                                                       }
1649                                                                  }
1650                                                                if (st->cb.item_free.func)
1651                                                                  {
1652                                                                     st->cb.item_free.func(st->cb.item_free.data, remove_item->item_info);
1653                                                                     remove_item->item_info = NULL;
1654                                                                  }
1655
1656                                                                Eina_List *temp_header_list = header_list;
1657                                                                header_list = eina_list_remove(header_list, remove_item);
1658                                                                st->total_item_count--;
1659                                                                LKD(remove_item->lock);
1660                                                                elm_genlist_item_del(remove_item->item);
1661                                                                free(remove_item);
1662
1663                                                                if (eina_list_count(header_list) == 0)
1664                                                                  {
1665                                                                     st->header_items = eina_list_remove(st->header_items, temp_header_list);
1666                                                                  }
1667                                                                else if(eina_list_count(header_list) == 1)
1668                                                                  {
1669                                                                     Elm_Store_Item *temp_sti = eina_list_nth(header_list, 0);
1670                                                                     if(temp_sti && temp_sti->item_info)
1671                                                                       {
1672                                                                          if (temp_sti->item_info->item_type == ELM_GENLIST_ITEM_GROUP)
1673                                                                            {
1674                                                                               if (temp_sti->fetched)
1675                                                                                 {
1676                                                                                    int index = elm_store_item_index_get(temp_sti);
1677                                                                                    if (index != -1)
1678                                                                                      {
1679                                                                                         _item_unfetch(st, index);
1680                                                                                      }
1681                                                                                    else
1682                                                                                      {
1683                                                                                         return;
1684                                                                                      }
1685                                                                                 }
1686
1687                                                                               if (st->cb.item_free.func)
1688                                                                                 {
1689                                                                                    st->cb.item_free.func(st->cb.item_free.data, temp_sti->item_info);
1690                                                                                    temp_sti->item_info = NULL;
1691                                                                                 }
1692
1693                                                                               header_list = eina_list_remove(header_list, temp_sti);
1694                                                                               st->total_item_count--;
1695                                                                               LKD(temp_sti->lock);
1696                                                                               elm_genlist_item_del(temp_sti->item);
1697                                                                               free(temp_sti);
1698                                                                               st->header_items = eina_list_remove(st->header_items, temp_header_list);
1699                                                                            }
1700                                                                       }
1701                                                                  }
1702                                                                temp_header_list = NULL;
1703                                                                removed = EINA_TRUE;
1704                                                             }
1705                                                        }
1706                                                      else
1707                                                        {
1708                                                           break;
1709                                                        }
1710                                                   }
1711                                              }
1712                                         }
1713                                    }
1714                                  else if (header_item->item_info->group_index == sti->item_info->group_index)
1715                                    {
1716                                       Eina_Bool last_add = EINA_TRUE;
1717                                       Eina_List *in_l;
1718                                       Eina_List *in_l_next;
1719                                       Elm_Store_Item *comp_item;
1720
1721                                       EINA_LIST_FOREACH_SAFE(header_list, in_l, in_l_next, comp_item)
1722                                         {
1723                                            if(comp_item)
1724                                              {
1725                                                 if(last_add == EINA_FALSE)
1726                                                   {
1727                                                      comp_item->item_info->index++;
1728                                                   }
1729                                                 else
1730                                                   {
1731                                                      int sort;
1732                                                      if (st->cb.item_sort.func)
1733                                                        {
1734                                                           sort = st->cb.item_sort.func(st->cb.item_sort.data, sti->item_info, comp_item->item_info);
1735
1736                                                           if(sort == ELM_STORE_ITEM_SORT_LOW)
1737                                                             {
1738                                                                sti->item_info->index = comp_item->item_info->index;
1739                                                                comp_item->item_info->index++;
1740                                                                header_list = eina_list_prepend_relative(header_list, sti, comp_item);
1741                                                                st->total_item_count++;
1742                                                                sti->item = elm_genlist_item_insert_before(st->genlist,
1743                                                                                                           itc,
1744                                                                                                           sti,
1745                                                                                                           header_item->item,
1746                                                                                                           comp_item->item,
1747                                                                                                           ELM_GENLIST_ITEM_NONE,
1748                                                                                                           (Evas_Smart_Cb)sti->store->cb.item_select.func,
1749                                                                                                           (void *)sti->store->cb.item_select.data);
1750                                                                elm_store_item_update(sti);
1751                                                                last_add = EINA_FALSE;
1752                                                             }
1753                                                        }
1754                                                      else
1755                                                        {
1756                                                           Elm_Store_Item *last_sti = eina_list_nth(header_list, eina_list_count(header_list) - 1);
1757                                                           sti->item_info->index = eina_list_count(header_list);
1758                                                           header_list = eina_list_append(header_list, sti);
1759                                                           st->total_item_count++;
1760                                                           sti->item = elm_genlist_item_insert_after(st->genlist,
1761                                                                                                     itc,
1762                                                                                                     sti,
1763                                                                                                     header_item->item,
1764                                                                                                     last_sti->item,
1765                                                                                                     ELM_GENLIST_ITEM_NONE,
1766                                                                                                     (Evas_Smart_Cb)sti->store->cb.item_select.func,
1767                                                                                                     (void *)sti->store->cb.item_select.data);
1768                                                           elm_store_item_update(sti);
1769                                                           last_add = EINA_FALSE;
1770                                                           break;
1771                                                        }
1772                                                   }
1773                                              }
1774                                         }
1775                                       if(last_add)
1776                                         {
1777                                            Elm_Store_Item *last_sti = eina_list_nth(header_list, eina_list_count(header_list) - 1);
1778                                            sti->item_info->index = eina_list_count(header_list);
1779                                            header_list = eina_list_append(header_list, sti);
1780                                            st->total_item_count++;
1781                                            sti->item = elm_genlist_item_insert_after(st->genlist,
1782                                                                                      itc,
1783                                                                                      sti,
1784                                                                                      header_item->item,
1785                                                                                      last_sti->item,
1786                                                                                      ELM_GENLIST_ITEM_NONE,
1787                                                                                      (Evas_Smart_Cb)sti->store->cb.item_select.func,
1788                                                                                      (void *)sti->store->cb.item_select.data);
1789                                            elm_store_item_update(sti);
1790                                         }
1791                                    }
1792                               }
1793                          }
1794                     }
1795                }
1796           }
1797         else
1798           {
1799              if (st->header_items)
1800                {
1801                   Eina_Bool normal_add = EINA_TRUE;
1802                   Eina_List *l;
1803                   Eina_List *l_next;
1804                   Eina_List *header_list;
1805
1806                   EINA_LIST_FOREACH_SAFE(st->header_items, l, l_next, header_list)
1807                     {
1808                        if (header_list)
1809                          {
1810                             Elm_Store_Item *header_item = eina_list_nth(header_list, 0);
1811
1812                             if(header_item && header_item->item_info)
1813                               {
1814                                  if (header_item->item_info->group_index == sti->item_info->group_index)
1815                                    {
1816                                       Eina_List *in_l;
1817                                       Eina_List *in_l_next;
1818                                       Elm_Store_Item *comp_item;
1819
1820                                       EINA_LIST_FOREACH_SAFE(header_list, in_l, in_l_next, comp_item)
1821                                         {
1822                                            if (comp_item )
1823                                              {
1824                                                 if(normal_add == EINA_FALSE)
1825                                                   {
1826                                                      comp_item->item_info->index++;
1827                                                   }
1828                                                 else
1829                                                   {
1830                                                      int sort;
1831                                                      if (st->cb.item_sort.func)
1832                                                        {
1833                                                           sort = st->cb.item_sort.func(st->cb.item_sort.data, sti->item_info, comp_item->item_info);
1834
1835                                                           if(sort == ELM_STORE_ITEM_SORT_LOW)
1836                                                             {
1837                                                                sti->item_info->index = comp_item->item_info->index;
1838                                                                comp_item->item_info->index++;
1839                                                                header_list = eina_list_prepend_relative(header_list, sti, comp_item);
1840                                                                st->total_item_count++;
1841                                                                sti->item = elm_genlist_item_insert_before(st->genlist,
1842                                                                                                           itc,
1843                                                                                                           sti,
1844                                                                                                           header_item->item,
1845                                                                                                           comp_item->item,
1846                                                                                                           ELM_GENLIST_ITEM_NONE,
1847                                                                                                           (Evas_Smart_Cb)sti->store->cb.item_select.func,
1848                                                                                                           (void *)sti->store->cb.item_select.data);
1849                                                                normal_add = EINA_FALSE;
1850                                                                elm_store_item_update(sti);
1851                                                             }
1852                                                        }
1853                                                      else
1854                                                        {
1855                                                           Elm_Store_Item *last_sti = eina_list_nth(header_list, eina_list_count(header_list) - 1);
1856                                                           sti->item_info->index = eina_list_count(header_list);
1857                                                           header_list = eina_list_append(header_list, sti);
1858                                                           st->total_item_count++;
1859                                                           sti->item = elm_genlist_item_insert_after(st->genlist,
1860                                                                                                     itc,
1861                                                                                                     sti,
1862                                                                                                     header_item->item,
1863                                                                                                     last_sti->item,
1864                                                                                                     ELM_GENLIST_ITEM_NONE,
1865                                                                                                     (Evas_Smart_Cb)sti->store->cb.item_select.func,
1866                                                                                                     (void *)sti->store->cb.item_select.data);
1867                                                           normal_add = EINA_FALSE;
1868                                                           elm_store_item_update(sti);
1869                                                           break;
1870                                                        }
1871                                                   }
1872                                              }
1873                                         }
1874                                       if(normal_add)
1875                                         {
1876                                            Elm_Store_Item *last_sti = eina_list_nth(header_list, eina_list_count(header_list) - 1);
1877                                            sti->item_info->index = eina_list_count(header_list);
1878                                            header_list = eina_list_append(header_list, sti);
1879                                            st->total_item_count++;
1880                                            sti->item = elm_genlist_item_insert_after(st->genlist,
1881                                                                                      itc,
1882                                                                                      sti,
1883                                                                                      header_item->item,
1884                                                                                      last_sti->item,
1885                                                                                      ELM_GENLIST_ITEM_NONE,
1886                                                                                      (Evas_Smart_Cb)sti->store->cb.item_select.func,
1887                                                                                      (void *)sti->store->cb.item_select.data);
1888                                            normal_add = EINA_FALSE;
1889                                            elm_store_item_update(sti);
1890                                         }
1891                                       if(normal_add == EINA_FALSE)
1892                                         {
1893                                            break;
1894                                         }
1895                                    }
1896                               }
1897                          }
1898                     }
1899                   if (normal_add)
1900                     {
1901                        Eina_List *new_header_list = NULL;
1902                        sti->item_info->index = 0;
1903                        new_header_list = eina_list_append(new_header_list, sti);
1904                        st->total_item_count++;
1905                        st->header_items = eina_list_append(st->header_items, new_header_list);
1906                        sti->item = elm_genlist_item_append(st->genlist,
1907                                                            itc,
1908                                                            sti,
1909                                                            NULL,
1910                                                            ELM_GENLIST_ITEM_NONE,
1911                                                            (Evas_Smart_Cb)sti->store->cb.item_select.func,
1912                                                            (void *)sti->store->cb.item_select.data);
1913                        elm_store_item_update(sti);
1914                     }
1915                }
1916              else
1917                {
1918                   if (st->live)
1919                     {
1920                        Eina_List *new_header_list = NULL;
1921                        sti->item_info->index = 0;
1922                        new_header_list = eina_list_append(new_header_list, sti);
1923                        st->total_item_count++;
1924                        st->header_items = eina_list_append(st->header_items, new_header_list);
1925                        sti->item = elm_genlist_item_append(st->genlist,
1926                                                            itc,
1927                                                            sti,
1928                                                            NULL,
1929                                                            ELM_GENLIST_ITEM_NONE,
1930                                                            (Evas_Smart_Cb)sti->store->cb.item_select.func,
1931                                                            (void *)sti->store->cb.item_select.data);
1932                        elm_store_item_update(sti);
1933                     }
1934                }
1935           }
1936      }
1937 }
1938
1939 static void
1940 _item_free(Elm_Store_Item *sti)
1941 {
1942    if (!EINA_MAGIC_CHECK(sti, ELM_STORE_ITEM_MAGIC)) return;
1943    elm_store_item_del(sti);
1944 }
1945
1946 static void
1947 _store_free(Elm_Store *st)
1948 {
1949    if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return;
1950
1951    Elm_Store_DBsystem *std = (Elm_Store_DBsystem *)st;
1952    eina_stringshare_del(std->p_db);
1953    elm_store_free(st);
1954 }
1955
1956 /**
1957  * Add a new dbsystem Store object
1958  *
1959  * @return The new object or NULL if it cannot be created
1960  *
1961  * @ingroup Store
1962  */
1963 EAPI Elm_Store *
1964 elm_store_dbsystem_new(void)
1965 {
1966    Elm_Store_DBsystem *std = _store_new(Elm_Store_DBsystem);
1967    EINA_SAFETY_ON_NULL_RETURN_VAL(std, NULL);
1968
1969    EINA_MAGIC_SET(std, ELM_STORE_DBSYSTEM_MAGIC);
1970    std->base.free = _store_free;
1971    std->base.item.free = _item_free;
1972    return &std->base;
1973 }
1974
1975 /**
1976  * Sets the item count of a store
1977  *
1978  * @param st The store object
1979  * @param count The item count of an store
1980  *
1981  * @ingroup Store
1982  */
1983 EAPI void
1984 elm_store_item_count_set(Elm_Store *st, int count)
1985 {
1986    EINA_SAFETY_ON_NULL_RETURN(st);
1987    if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return;
1988
1989    st->item_count = count;
1990    if (count > 0)
1991      {
1992         st->multi_load = EINA_TRUE;
1993      }
1994    else
1995      {
1996         st->multi_load = EINA_FALSE;
1997      }
1998 }
1999
2000
2001 /**
2002  * Set the select func that select the state of a list item whether true or false
2003  *
2004  * @param st The store object
2005  * @param func The select cb function of an store
2006  * @param data The new data pointer to set
2007  *
2008  * @ingroup Store
2009  */
2010 EAPI void
2011 elm_store_item_select_func_set(Elm_Store *st, Elm_Store_Item_Select_Cb func, const void *data)
2012 {
2013    EINA_SAFETY_ON_NULL_RETURN(st);
2014    if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return;
2015
2016    st->cb.item_select.func = func;
2017    st->cb.item_select.data = (void *)data;
2018 }
2019
2020 /**
2021  * Sets the sort func that sort the item with a next in the list
2022  *
2023  * @param st The store object
2024  * @param func The sort cb function of an store
2025  * @param data The new data pointer to set
2026  *
2027  * @ingroup Store
2028  */
2029 EAPI void
2030 elm_store_item_sort_func_set(Elm_Store *st, Elm_Store_Item_Sort_Cb func, const void *data)
2031 {
2032    EINA_SAFETY_ON_NULL_RETURN(st);
2033    if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return;
2034
2035    st->cb.item_sort.func = func;
2036    st->cb.item_sort.data = (void *)data;
2037 }
2038
2039 /**
2040  * Set the store item free func
2041  *
2042  * @param st The store object
2043  * @param func The free cb function of an store
2044  * @param data The new data pointer to set
2045  *
2046  * @ingroup Store
2047  */
2048 EAPI void
2049 elm_store_item_free_func_set(Elm_Store *st, Elm_Store_Item_Free_Cb func, const void *data)
2050 {
2051    EINA_SAFETY_ON_NULL_RETURN(st);
2052    if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return;
2053
2054    st->cb.item_free.func = func;
2055    st->cb.item_free.data = (void *)data;
2056 }
2057
2058 /**
2059  * Get the item index that included header items
2060  *
2061  * @param sti The store item object
2062  * @return The item index in genlist
2063  *
2064  * @ingroup Store
2065  */
2066 EAPI int
2067 elm_store_item_index_get(const Elm_Store_Item *sti)
2068 {
2069    EINA_SAFETY_ON_NULL_RETURN_VAL(sti, -1);
2070    if (!EINA_MAGIC_CHECK(sti, ELM_STORE_ITEM_MAGIC)) return -1;
2071    Elm_Store *st = sti->store;
2072
2073    if (st->live)
2074      {
2075         int index = 0;
2076         Eina_List *l;
2077         Eina_List *l_next;
2078         Eina_List *header_list;
2079
2080         EINA_LIST_FOREACH_SAFE(st->header_items, l, l_next, header_list)
2081           {
2082              if (header_list)
2083                {
2084                   Elm_Store_Item *temp_sti = eina_list_nth(header_list, 0);
2085                   if(temp_sti && temp_sti->item_info && sti->item_info)
2086                     {
2087                        if (sti->item_info->group_index == temp_sti->item_info->group_index)
2088                          {
2089                             Eina_List *in_l;
2090                             Eina_List *in_l_next;
2091                             Elm_Store_Item *comp_item;
2092
2093                             EINA_LIST_FOREACH_SAFE(header_list, in_l, in_l_next, comp_item)
2094                               {
2095                                  if(comp_item)
2096                                    {
2097                                       if (comp_item->item_info->index == sti->item_info->index)
2098                                         {
2099                                            return index;
2100                                         }
2101                                       else
2102                                         {
2103                                            index++;
2104                                         }
2105                                    }
2106                               }
2107                          }
2108                        else
2109                          {
2110                             index = index + eina_list_count(header_list);
2111                          }
2112                     }
2113                }
2114           }
2115         return -1;
2116      }
2117    else
2118      {
2119         return -1;
2120      }
2121 }
2122
2123 /**
2124  * Get the item index of real data that don't included header items
2125  *
2126  * @param sti The store item object
2127  * @return The real item index
2128  *
2129  * @ingroup Store
2130  */
2131 EAPI int
2132 elm_store_item_data_index_get(const Elm_Store_Item *sti)
2133 {
2134    EINA_SAFETY_ON_NULL_RETURN_VAL(sti, -1);
2135    if (!EINA_MAGIC_CHECK(sti, ELM_STORE_ITEM_MAGIC)) return -1;
2136    Elm_Store *st = sti->store;
2137
2138    if (st->live)
2139      {
2140         if (sti->item_info->item_type == ELM_GENLIST_ITEM_NONE)
2141           {
2142              int index = 0;
2143              int group_item_count = 0;
2144              Eina_List *l;
2145              Eina_List *l_next;
2146              Eina_List *header_list;
2147
2148              EINA_LIST_FOREACH_SAFE(st->header_items, l, l_next, header_list)
2149                {
2150                   if (header_list)
2151                     {
2152                        Elm_Store_Item *temp_sti = eina_list_nth(header_list, 0);
2153                        if(temp_sti && temp_sti->item_info && sti->item_info)
2154                          {
2155
2156                             if(temp_sti->item_info->item_type == ELM_GENLIST_ITEM_GROUP)
2157                               {
2158                                  group_item_count++;
2159                               }
2160
2161                             if (temp_sti->item_info->group_index == sti->item_info->group_index)
2162                               {
2163                                  Eina_List *in_l;
2164                                  Eina_List *in_l_next;
2165                                  Elm_Store_Item *comp_item;
2166
2167                                  EINA_LIST_FOREACH_SAFE(header_list, in_l, in_l_next, comp_item)
2168                                    {
2169                                       if(comp_item)
2170                                         {
2171                                            if (comp_item->item_info->index == sti->item_info->index)
2172                                              {
2173                                                 return (index - group_item_count);
2174                                              }
2175                                            else
2176                                              {
2177                                                 index++;
2178                                              }
2179                                         }
2180                                    }
2181                               }
2182                          }
2183                        else
2184                          {
2185                             index = index + eina_list_count(header_list);
2186                          }
2187                     }
2188                }
2189           }
2190         return -1;
2191      }
2192    else
2193      {
2194         return -1;
2195      }
2196 }
2197
2198 /**
2199  * Get the DB pointer of an item
2200  *
2201  * @param sti The store item object
2202  * @return The DB pointer of item
2203  *
2204  * @ingroup Store
2205  */
2206 EAPI void *
2207 elm_store_dbsystem_db_get(const Elm_Store_Item *sti)
2208 {
2209    if (!EINA_MAGIC_CHECK(sti, ELM_STORE_ITEM_MAGIC)) return NULL;
2210
2211    const Elm_Store_DBsystem *std = (const Elm_Store_DBsystem *)sti->store;
2212    if (!EINA_MAGIC_CHECK(sti->store, ELM_STORE_MAGIC)) return NULL;
2213    if (!EINA_MAGIC_CHECK(std, ELM_STORE_DBSYSTEM_MAGIC)) return NULL;
2214    return std->p_db;
2215 }
2216
2217 /**
2218  * Set the DB pointer of an item
2219  *
2220  * @param sti The store item object
2221  * @parm p_db The DB pointer of item
2222  *
2223  * @ingroup Store
2224  */
2225 EAPI void
2226 elm_store_dbsystem_db_set(Elm_Store *store, void *p_db)
2227 {
2228    Elm_Store_DBsystem *std = (Elm_Store_DBsystem *)store;
2229    if (!EINA_MAGIC_CHECK(store, ELM_STORE_MAGIC)) return;
2230    if (!EINA_MAGIC_CHECK(std, ELM_STORE_DBSYSTEM_MAGIC)) return;
2231
2232    std->p_db = p_db;
2233
2234    if (store->list_th)
2235      {
2236         ecore_thread_cancel(store->list_th);
2237         store->list_th = NULL;
2238      }
2239    store->list_th = ecore_thread_feedback_run(_list_do, _list_update, _list_end, _list_cancel, store, EINA_TRUE);
2240 }
2241
2242 /**
2243  * Append the item to the genlist
2244  *
2245  * @param st The store object
2246  * @param info The store item info dbsystem object
2247  * @return The item of store
2248  *
2249  * @ingroup Store
2250  */
2251 EAPI Elm_Store_Item *
2252 elm_store_item_add(Elm_Store *st, Elm_Store_Item_Info *info)
2253 {
2254    EINA_SAFETY_ON_NULL_RETURN_VAL(st, NULL);
2255    if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return NULL;
2256    EINA_SAFETY_ON_NULL_RETURN_VAL(info, NULL);
2257    Elm_Store_Item *sti;
2258    Elm_Genlist_Item_Class *itc;
2259
2260    sti = calloc(1, sizeof(Elm_Store_Item));
2261    if (!sti) return NULL;
2262
2263    LKI(sti->lock);
2264    EINA_MAGIC_SET(sti, ELM_STORE_ITEM_MAGIC);
2265
2266    sti->store = st;
2267    sti->item_info = info;
2268    sti->fetched = EINA_FALSE;
2269
2270    itc = info->item_class;
2271    if (!itc) itc = &_store_item_class;
2272    else
2273      {
2274         itc->func.label_get = (GenlistItemLabelGetFunc)_item_label_get;
2275         itc->func.icon_get = (GenlistItemIconGetFunc)_item_icon_get;
2276         itc->func.state_get = NULL;
2277         itc->func.del = NULL;
2278      }
2279
2280    if (st->live)
2281      {
2282         if (sti->item_info->item_type == ELM_GENLIST_ITEM_GROUP)
2283           {
2284              _group_item_append(sti, itc);
2285           }
2286         else
2287           {
2288              _normal_item_append(sti, itc);
2289           }
2290         return sti;
2291      }
2292    else
2293      {
2294         return NULL;
2295      }
2296 }
2297
2298 /**
2299  * Realize the visible items to the screen
2300  *
2301  * @param st The store object
2302  *
2303  * @ingroup Store
2304  */
2305 EAPI void
2306 elm_store_visible_items_update(Elm_Store *st)
2307 {
2308    EINA_SAFETY_ON_NULL_RETURN(st);
2309    if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return;
2310
2311    Eina_List *realized_list = elm_genlist_realized_items_get(st->genlist);
2312    if(realized_list)
2313      {
2314         Eina_List *l;
2315         Elm_Genlist_Item *it;
2316         EINA_LIST_FOREACH(realized_list, l, it)
2317           {
2318              if(it)
2319                {
2320                   Elm_Store_Item *realized_sti = elm_genlist_item_data_get(it);
2321                   int index = elm_store_item_index_get(realized_sti);
2322                   if (index != -1)
2323                     {
2324                        if(realized_sti->fetched)
2325                          {
2326                             _item_unfetch(st, index);
2327                          }
2328                        _item_fetch(st, index);
2329                        if (realized_sti->data) elm_genlist_item_update(realized_sti->item);
2330                     }
2331                   else
2332                     {
2333                        return;
2334                     }
2335                }
2336           }
2337      }
2338 }
2339
2340 /**
2341  * Realize the item to the screen
2342  *
2343  * @param sti The store item object
2344  *
2345  * @ingroup Store
2346  */
2347 EAPI void
2348 elm_store_item_update(Elm_Store_Item *sti)
2349 {
2350    EINA_SAFETY_ON_NULL_RETURN(sti);
2351    if (!EINA_MAGIC_CHECK(sti, ELM_STORE_ITEM_MAGIC)) return;
2352    Elm_Store *st = sti->store;
2353
2354    int index = elm_store_item_index_get(sti);
2355    if (index != -1)
2356      {
2357         if ((st->start_fetch_index <= index) && (index <= (st->start_fetch_index + st->cache_max)))
2358           {
2359              if (sti->fetched)
2360                {
2361                   _item_unfetch(st, index);
2362                }
2363              _item_fetch(st, index);
2364
2365              if(st->end_fetch_index < (st->total_item_count-1))
2366                {
2367                   if( (st->end_fetch_index - st->cache_max) == st->start_fetch_index)
2368                     {
2369                        _item_unfetch(st, (st->total_item_count-1));
2370                     }
2371                   else
2372                     {
2373                        st->end_fetch_index = (st->total_item_count-1);
2374                     }
2375                }
2376              if(sti->data) elm_genlist_item_update(sti->item);
2377           }
2378      }
2379    else
2380      {
2381         return;
2382      }
2383 }
2384
2385 /**
2386  * Delete the item of genlist
2387  *
2388  * @param sti The store item object
2389  *
2390  * @ingroup Store
2391  */
2392 EAPI void
2393 elm_store_item_del(Elm_Store_Item *sti)
2394 {
2395    EINA_SAFETY_ON_NULL_RETURN(sti);
2396    if (!EINA_MAGIC_CHECK(sti, ELM_STORE_ITEM_MAGIC)) return;
2397    Elm_Store *st = sti->store;
2398
2399    Eina_List *l;
2400    Eina_List*l_next;
2401    Eina_List *header_list;
2402
2403    if (st->live)
2404      {
2405         EINA_LIST_FOREACH_SAFE(st->header_items, l, l_next, header_list)
2406           {
2407              if (header_list)
2408                {
2409                   Elm_Store_Item *header_item = eina_list_nth(header_list, 0);
2410                   if(header_item && header_item->item_info && sti->item_info)
2411                     {
2412
2413                        if (header_item->item_info->group_index == sti->item_info->group_index)
2414                          {
2415                             Eina_Bool removed = EINA_FALSE;
2416                             Eina_List *in_l;
2417                             Eina_List *in_l_next;
2418                             Elm_Store_Item *remove_sti;
2419                             EINA_LIST_FOREACH_SAFE(header_list, in_l, in_l_next, remove_sti)
2420                               {
2421                                  if(remove_sti)
2422                                    {
2423                                       if (removed == EINA_TRUE)
2424                                         {
2425                                            remove_sti->item_info->index--;
2426                                         }
2427                                       else
2428                                         {
2429                                            if (remove_sti->item_info->index == sti->item_info->index)
2430                                              {
2431                                                 if (remove_sti->fetched)
2432                                                   {
2433                                                      int index = elm_store_item_index_get(remove_sti);
2434                                                      if (index != -1)
2435                                                        {
2436                                                           _item_unfetch(st, index);
2437                                                        }
2438                                                      else
2439                                                        {
2440                                                           return;
2441                                                        }
2442                                                   }
2443                                                 if (st->cb.item_free.func)
2444                                                   {
2445                                                      st->cb.item_free.func(st->cb.item_free.data, remove_sti->item_info);
2446                                                      remove_sti->item_info = NULL;
2447                                                   }
2448
2449                                                 Eina_List *temp_header_list = header_list;
2450                                                 header_list = eina_list_remove(header_list, remove_sti);
2451                                                 st->total_item_count--;
2452                                                 LKD(remove_sti->lock);
2453                                                 elm_genlist_item_del(remove_sti->item);
2454                                                 free(remove_sti);
2455
2456                                                 if (eina_list_count(header_list) == 0)
2457                                                   {
2458                                                      st->header_items = eina_list_remove(st->header_items, temp_header_list);
2459                                                   }
2460                                                 else if (eina_list_count(header_list) == 1)
2461                                                   {
2462                                                      Elm_Store_Item *temp_sti = eina_list_nth(header_list, 0);
2463                                                      if(temp_sti && temp_sti->item_info)
2464                                                        {
2465                                                           if (temp_sti->item_info->item_type == ELM_GENLIST_ITEM_GROUP)
2466                                                             {
2467                                                                if (temp_sti->fetched)
2468                                                                  {
2469                                                                     int index = elm_store_item_index_get(temp_sti);
2470                                                                     if (index != -1)
2471                                                                       {
2472                                                                          _item_unfetch(st, index);
2473                                                                       }
2474                                                                     else
2475                                                                       {
2476                                                                          return;
2477                                                                       }
2478                                                                  }
2479                                                                if (st->cb.item_free.func)
2480                                                                  {
2481                                                                     st->cb.item_free.func(st->cb.item_free.data, temp_sti->item_info);
2482                                                                     temp_sti->item_info = NULL;
2483                                                                  }
2484
2485                                                                header_list = eina_list_remove(header_list, temp_sti);
2486                                                                st->total_item_count--;
2487                                                                LKD(temp_sti->lock);
2488                                                                elm_genlist_item_del(temp_sti->item);
2489                                                                free(temp_sti);
2490                                                                st->header_items = eina_list_remove(st->header_items, temp_header_list);
2491                                                             }
2492                                                        }
2493                                                   }
2494                                                 temp_header_list = NULL;
2495                                                 removed = EINA_TRUE;
2496                                              }
2497                                         }
2498                                    }
2499                               }
2500                          }
2501                     }
2502                }
2503           }
2504      }
2505 }
2506
2507 // TODO: END -DBsystem store
2508