Merge branch 'master' into svn_merge
[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                                                                          break;
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                                                                if (eina_list_count(header_list) == 1)
1657                                                                  {
1658                                                                     st->header_items = eina_list_remove(st->header_items, header_list);
1659                                                                     header_list = eina_list_free(header_list);
1660                                                                     st->total_item_count--;
1661                                                                     LKD(remove_item->lock);
1662                                                                     elm_genlist_item_del(remove_item->item);
1663                                                                     free(remove_item);
1664                                                                     break;
1665                                                                  }
1666                                                                else
1667                                                                  {
1668                                                                     header_list = eina_list_remove(header_list, remove_item);
1669                                                                     st->total_item_count--;
1670                                                                     LKD(remove_item->lock);
1671                                                                     elm_genlist_item_del(remove_item->item);
1672                                                                     free(remove_item);
1673                                                                  }
1674
1675                                                                if(eina_list_count(header_list) == 1)
1676                                                                  {
1677                                                                     Elm_Store_Item *t_sti = eina_list_nth(header_list, 0);
1678                                                                     if(t_sti && t_sti->item_info)
1679                                                                       {
1680                                                                          if (t_sti->item_info->item_type == ELM_GENLIST_ITEM_GROUP)
1681                                                                            {
1682                                                                               if (t_sti->fetched)
1683                                                                                 {
1684                                                                                    int index = elm_store_item_index_get(t_sti);
1685                                                                                    if (index != -1)
1686                                                                                      {
1687                                                                                         _item_unfetch(st, index);
1688                                                                                      }
1689                                                                                    else
1690                                                                                      {
1691                                                                                         break;
1692                                                                                      }
1693                                                                                 }
1694
1695                                                                               if (st->cb.item_free.func)
1696                                                                                 {
1697                                                                                    st->cb.item_free.func(st->cb.item_free.data, t_sti->item_info);
1698                                                                                    t_sti->item_info = NULL;
1699                                                                                 }
1700                                                                               st->header_items = eina_list_remove(st->header_items, header_list);
1701                                                                               header_list = eina_list_free(header_list);
1702                                                                               st->total_item_count--;
1703                                                                               LKD(t_sti->lock);
1704                                                                               elm_genlist_item_del(t_sti->item);
1705                                                                               free(t_sti);
1706                                                                            }
1707                                                                       }
1708                                                                  }
1709                                                                removed = EINA_TRUE;
1710                                                             }
1711                                                        }
1712                                                      else
1713                                                        {
1714                                                           break;
1715                                                        }
1716                                                   }
1717                                              }
1718                                         }
1719                                    }
1720                                  else if (header_item->item_info->group_index == sti->item_info->group_index)
1721                                    {
1722                                       Eina_Bool last_add = EINA_TRUE;
1723                                       Eina_List *in_l;
1724                                       Eina_List *in_l_next;
1725                                       Elm_Store_Item *comp_item;
1726
1727                                       EINA_LIST_FOREACH_SAFE(header_list, in_l, in_l_next, comp_item)
1728                                         {
1729                                            if(comp_item)
1730                                              {
1731                                                 if(last_add == EINA_FALSE)
1732                                                   {
1733                                                      comp_item->item_info->index++;
1734                                                   }
1735                                                 else
1736                                                   {
1737                                                      int sort;
1738                                                      if (st->cb.item_sort.func)
1739                                                        {
1740                                                           sort = st->cb.item_sort.func(st->cb.item_sort.data, sti->item_info, comp_item->item_info);
1741
1742                                                           if(sort == ELM_STORE_ITEM_SORT_LOW)
1743                                                             {
1744                                                                sti->item_info->index = comp_item->item_info->index;
1745                                                                comp_item->item_info->index++;
1746                                                                header_list = eina_list_prepend_relative(header_list, sti, comp_item);
1747                                                                st->total_item_count++;
1748                                                                sti->item = elm_genlist_item_insert_before(st->genlist,
1749                                                                                                           itc,
1750                                                                                                           sti,
1751                                                                                                           header_item->item,
1752                                                                                                           comp_item->item,
1753                                                                                                           ELM_GENLIST_ITEM_NONE,
1754                                                                                                           (Evas_Smart_Cb)sti->store->cb.item_select.func,
1755                                                                                                           (void *)sti->store->cb.item_select.data);
1756                                                                elm_store_item_update(sti);
1757                                                                last_add = EINA_FALSE;
1758                                                             }
1759                                                        }
1760                                                      else
1761                                                        {
1762                                                           Elm_Store_Item *last_sti = eina_list_nth(header_list, eina_list_count(header_list) - 1);
1763                                                           sti->item_info->index = eina_list_count(header_list);
1764                                                           header_list = eina_list_append(header_list, sti);
1765                                                           st->total_item_count++;
1766                                                           sti->item = elm_genlist_item_insert_after(st->genlist,
1767                                                                                                     itc,
1768                                                                                                     sti,
1769                                                                                                     header_item->item,
1770                                                                                                     last_sti->item,
1771                                                                                                     ELM_GENLIST_ITEM_NONE,
1772                                                                                                     (Evas_Smart_Cb)sti->store->cb.item_select.func,
1773                                                                                                     (void *)sti->store->cb.item_select.data);
1774                                                           elm_store_item_update(sti);
1775                                                           last_add = EINA_FALSE;
1776                                                           break;
1777                                                        }
1778                                                   }
1779                                              }
1780                                         }
1781                                       if(last_add)
1782                                         {
1783                                            Elm_Store_Item *last_sti = eina_list_nth(header_list, eina_list_count(header_list) - 1);
1784                                            sti->item_info->index = eina_list_count(header_list);
1785                                            header_list = eina_list_append(header_list, sti);
1786                                            st->total_item_count++;
1787                                            sti->item = elm_genlist_item_insert_after(st->genlist,
1788                                                                                      itc,
1789                                                                                      sti,
1790                                                                                      header_item->item,
1791                                                                                      last_sti->item,
1792                                                                                      ELM_GENLIST_ITEM_NONE,
1793                                                                                      (Evas_Smart_Cb)sti->store->cb.item_select.func,
1794                                                                                      (void *)sti->store->cb.item_select.data);
1795                                            elm_store_item_update(sti);
1796                                         }
1797                                    }
1798                               }
1799                          }
1800                     }
1801                }
1802           }
1803         else
1804           {
1805              if (st->header_items)
1806                {
1807                   Eina_Bool normal_add = EINA_TRUE;
1808                   Eina_List *l;
1809                   Eina_List *l_next;
1810                   Eina_List *header_list;
1811
1812                   EINA_LIST_FOREACH_SAFE(st->header_items, l, l_next, header_list)
1813                     {
1814                        if (header_list)
1815                          {
1816                             Elm_Store_Item *header_item = eina_list_nth(header_list, 0);
1817
1818                             if(header_item && header_item->item_info)
1819                               {
1820                                  if (header_item->item_info->group_index == sti->item_info->group_index)
1821                                    {
1822                                       Eina_List *in_l;
1823                                       Eina_List *in_l_next;
1824                                       Elm_Store_Item *comp_item;
1825
1826                                       EINA_LIST_FOREACH_SAFE(header_list, in_l, in_l_next, comp_item)
1827                                         {
1828                                            if (comp_item )
1829                                              {
1830                                                 if(normal_add == EINA_FALSE)
1831                                                   {
1832                                                      comp_item->item_info->index++;
1833                                                   }
1834                                                 else
1835                                                   {
1836                                                      int sort;
1837                                                      if (st->cb.item_sort.func)
1838                                                        {
1839                                                           sort = st->cb.item_sort.func(st->cb.item_sort.data, sti->item_info, comp_item->item_info);
1840
1841                                                           if(sort == ELM_STORE_ITEM_SORT_LOW)
1842                                                             {
1843                                                                sti->item_info->index = comp_item->item_info->index;
1844                                                                comp_item->item_info->index++;
1845                                                                header_list = eina_list_prepend_relative(header_list, sti, comp_item);
1846                                                                st->total_item_count++;
1847                                                                sti->item = elm_genlist_item_insert_before(st->genlist,
1848                                                                                                           itc,
1849                                                                                                           sti,
1850                                                                                                           header_item->item,
1851                                                                                                           comp_item->item,
1852                                                                                                           ELM_GENLIST_ITEM_NONE,
1853                                                                                                           (Evas_Smart_Cb)sti->store->cb.item_select.func,
1854                                                                                                           (void *)sti->store->cb.item_select.data);
1855                                                                normal_add = EINA_FALSE;
1856                                                                elm_store_item_update(sti);
1857                                                             }
1858                                                        }
1859                                                      else
1860                                                        {
1861                                                           Elm_Store_Item *last_sti = eina_list_nth(header_list, eina_list_count(header_list) - 1);
1862                                                           sti->item_info->index = eina_list_count(header_list);
1863                                                           header_list = eina_list_append(header_list, sti);
1864                                                           st->total_item_count++;
1865                                                           sti->item = elm_genlist_item_insert_after(st->genlist,
1866                                                                                                     itc,
1867                                                                                                     sti,
1868                                                                                                     header_item->item,
1869                                                                                                     last_sti->item,
1870                                                                                                     ELM_GENLIST_ITEM_NONE,
1871                                                                                                     (Evas_Smart_Cb)sti->store->cb.item_select.func,
1872                                                                                                     (void *)sti->store->cb.item_select.data);
1873                                                           normal_add = EINA_FALSE;
1874                                                           elm_store_item_update(sti);
1875                                                           break;
1876                                                        }
1877                                                   }
1878                                              }
1879                                         }
1880                                       if(normal_add)
1881                                         {
1882                                            Elm_Store_Item *last_sti = eina_list_nth(header_list, eina_list_count(header_list) - 1);
1883                                            sti->item_info->index = eina_list_count(header_list);
1884                                            header_list = eina_list_append(header_list, sti);
1885                                            st->total_item_count++;
1886                                            sti->item = elm_genlist_item_insert_after(st->genlist,
1887                                                                                      itc,
1888                                                                                      sti,
1889                                                                                      header_item->item,
1890                                                                                      last_sti->item,
1891                                                                                      ELM_GENLIST_ITEM_NONE,
1892                                                                                      (Evas_Smart_Cb)sti->store->cb.item_select.func,
1893                                                                                      (void *)sti->store->cb.item_select.data);
1894                                            normal_add = EINA_FALSE;
1895                                            elm_store_item_update(sti);
1896                                         }
1897                                       if(normal_add == EINA_FALSE)
1898                                         {
1899                                            break;
1900                                         }
1901                                    }
1902                               }
1903                          }
1904                     }
1905                   if (normal_add)
1906                     {
1907                        Eina_List *new_header_list = NULL;
1908                        sti->item_info->index = 0;
1909                        new_header_list = eina_list_append(new_header_list, sti);
1910                        st->total_item_count++;
1911                        st->header_items = eina_list_append(st->header_items, new_header_list);
1912                        sti->item = elm_genlist_item_append(st->genlist,
1913                                                            itc,
1914                                                            sti,
1915                                                            NULL,
1916                                                            ELM_GENLIST_ITEM_NONE,
1917                                                            (Evas_Smart_Cb)sti->store->cb.item_select.func,
1918                                                            (void *)sti->store->cb.item_select.data);
1919                        elm_store_item_update(sti);
1920                     }
1921                }
1922              else
1923                {
1924                   if (st->live)
1925                     {
1926                        Eina_List *new_header_list = NULL;
1927                        sti->item_info->index = 0;
1928                        new_header_list = eina_list_append(new_header_list, sti);
1929                        st->total_item_count++;
1930                        st->header_items = eina_list_append(st->header_items, new_header_list);
1931                        sti->item = elm_genlist_item_append(st->genlist,
1932                                                            itc,
1933                                                            sti,
1934                                                            NULL,
1935                                                            ELM_GENLIST_ITEM_NONE,
1936                                                            (Evas_Smart_Cb)sti->store->cb.item_select.func,
1937                                                            (void *)sti->store->cb.item_select.data);
1938                        elm_store_item_update(sti);
1939                     }
1940                }
1941           }
1942      }
1943 }
1944
1945 static void
1946 _item_free(Elm_Store_Item *sti)
1947 {
1948    if (!EINA_MAGIC_CHECK(sti, ELM_STORE_ITEM_MAGIC)) return;
1949    elm_store_item_del(sti);
1950 }
1951
1952 static void
1953 _store_free(Elm_Store *st)
1954 {
1955    if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return;
1956
1957    Elm_Store_DBsystem *std = (Elm_Store_DBsystem *)st;
1958    eina_stringshare_del(std->p_db);
1959    elm_store_free(st);
1960 }
1961
1962 /**
1963  * Add a new dbsystem Store object
1964  *
1965  * @return The new object or NULL if it cannot be created
1966  *
1967  * @ingroup Store
1968  */
1969 EAPI Elm_Store *
1970 elm_store_dbsystem_new(void)
1971 {
1972    Elm_Store_DBsystem *std = _store_new(Elm_Store_DBsystem);
1973    EINA_SAFETY_ON_NULL_RETURN_VAL(std, NULL);
1974
1975    EINA_MAGIC_SET(std, ELM_STORE_DBSYSTEM_MAGIC);
1976    std->base.free = _store_free;
1977    std->base.item.free = _item_free;
1978    return &std->base;
1979 }
1980
1981 /**
1982  * Sets the item count of a store
1983  *
1984  * @param st The store object
1985  * @param count The item count of an store
1986  *
1987  * @ingroup Store
1988  */
1989 EAPI void
1990 elm_store_item_count_set(Elm_Store *st, int count)
1991 {
1992    EINA_SAFETY_ON_NULL_RETURN(st);
1993    if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return;
1994
1995    st->item_count = count;
1996    if (count > 0)
1997      {
1998         st->multi_load = EINA_TRUE;
1999      }
2000    else
2001      {
2002         st->multi_load = EINA_FALSE;
2003      }
2004 }
2005
2006
2007 /**
2008  * Set the select func that select the state of a list item whether true or false
2009  *
2010  * @param st The store object
2011  * @param func The select cb function of an store
2012  * @param data The new data pointer to set
2013  *
2014  * @ingroup Store
2015  */
2016 EAPI void
2017 elm_store_item_select_func_set(Elm_Store *st, Elm_Store_Item_Select_Cb func, const void *data)
2018 {
2019    EINA_SAFETY_ON_NULL_RETURN(st);
2020    if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return;
2021
2022    st->cb.item_select.func = func;
2023    st->cb.item_select.data = (void *)data;
2024 }
2025
2026 /**
2027  * Sets the sort func that sort the item with a next in the list
2028  *
2029  * @param st The store object
2030  * @param func The sort cb function of an store
2031  * @param data The new data pointer to set
2032  *
2033  * @ingroup Store
2034  */
2035 EAPI void
2036 elm_store_item_sort_func_set(Elm_Store *st, Elm_Store_Item_Sort_Cb func, const void *data)
2037 {
2038    EINA_SAFETY_ON_NULL_RETURN(st);
2039    if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return;
2040
2041    st->cb.item_sort.func = func;
2042    st->cb.item_sort.data = (void *)data;
2043 }
2044
2045 /**
2046  * Set the store item free func
2047  *
2048  * @param st The store object
2049  * @param func The free cb function of an store
2050  * @param data The new data pointer to set
2051  *
2052  * @ingroup Store
2053  */
2054 EAPI void
2055 elm_store_item_free_func_set(Elm_Store *st, Elm_Store_Item_Free_Cb func, const void *data)
2056 {
2057    EINA_SAFETY_ON_NULL_RETURN(st);
2058    if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return;
2059
2060    st->cb.item_free.func = func;
2061    st->cb.item_free.data = (void *)data;
2062 }
2063
2064 /**
2065  * Get the item index that included header items
2066  *
2067  * @param sti The store item object
2068  * @return The item index in genlist
2069  *
2070  * @ingroup Store
2071  */
2072 EAPI int
2073 elm_store_item_index_get(const Elm_Store_Item *sti)
2074 {
2075    EINA_SAFETY_ON_NULL_RETURN_VAL(sti, -1);
2076    if (!EINA_MAGIC_CHECK(sti, ELM_STORE_ITEM_MAGIC)) return -1;
2077    Elm_Store *st = sti->store;
2078
2079    if (st->live)
2080      {
2081         int index = 0;
2082         Eina_List *l;
2083         Eina_List *l_next;
2084         Eina_List *header_list;
2085
2086         EINA_LIST_FOREACH_SAFE(st->header_items, l, l_next, header_list)
2087           {
2088              if (header_list)
2089                {
2090                   Elm_Store_Item *temp_sti = eina_list_nth(header_list, 0);
2091                   if(temp_sti && temp_sti->item_info && sti->item_info)
2092                     {
2093                        if (sti->item_info->group_index == temp_sti->item_info->group_index)
2094                          {
2095                             Eina_List *in_l;
2096                             Eina_List *in_l_next;
2097                             Elm_Store_Item *comp_item;
2098
2099                             EINA_LIST_FOREACH_SAFE(header_list, in_l, in_l_next, comp_item)
2100                               {
2101                                  if(comp_item)
2102                                    {
2103                                       if (comp_item->item_info->index == sti->item_info->index)
2104                                         {
2105                                            return index;
2106                                         }
2107                                       else
2108                                         {
2109                                            index++;
2110                                         }
2111                                    }
2112                               }
2113                          }
2114                        else
2115                          {
2116                             index = index + eina_list_count(header_list);
2117                          }
2118                     }
2119                }
2120           }
2121         return -1;
2122      }
2123    else
2124      {
2125         return -1;
2126      }
2127 }
2128
2129 /**
2130  * Get the item index of real data that don't included header items
2131  *
2132  * @param sti The store item object
2133  * @return The real item index
2134  *
2135  * @ingroup Store
2136  */
2137 EAPI int
2138 elm_store_item_data_index_get(const Elm_Store_Item *sti)
2139 {
2140    EINA_SAFETY_ON_NULL_RETURN_VAL(sti, -1);
2141    if (!EINA_MAGIC_CHECK(sti, ELM_STORE_ITEM_MAGIC)) return -1;
2142    Elm_Store *st = sti->store;
2143
2144    if (st->live)
2145      {
2146         if (sti->item_info->item_type == ELM_GENLIST_ITEM_NONE)
2147           {
2148              int index = 0;
2149              int group_item_count = 0;
2150              Eina_List *l;
2151              Eina_List *l_next;
2152              Eina_List *header_list;
2153
2154              EINA_LIST_FOREACH_SAFE(st->header_items, l, l_next, header_list)
2155                {
2156                   if (header_list)
2157                     {
2158                        Elm_Store_Item *temp_sti = eina_list_nth(header_list, 0);
2159                        if(temp_sti && temp_sti->item_info && sti->item_info)
2160                          {
2161
2162                             if(temp_sti->item_info->item_type == ELM_GENLIST_ITEM_GROUP)
2163                               {
2164                                  group_item_count++;
2165                               }
2166
2167                             if (temp_sti->item_info->group_index == sti->item_info->group_index)
2168                               {
2169                                  Eina_List *in_l;
2170                                  Eina_List *in_l_next;
2171                                  Elm_Store_Item *comp_item;
2172
2173                                  EINA_LIST_FOREACH_SAFE(header_list, in_l, in_l_next, comp_item)
2174                                    {
2175                                       if(comp_item)
2176                                         {
2177                                            if (comp_item->item_info->index == sti->item_info->index)
2178                                              {
2179                                                 return (index - group_item_count);
2180                                              }
2181                                            else
2182                                              {
2183                                                 index++;
2184                                              }
2185                                         }
2186                                    }
2187                               }
2188                          }
2189                        else
2190                          {
2191                             index = index + eina_list_count(header_list);
2192                          }
2193                     }
2194                }
2195           }
2196         return -1;
2197      }
2198    else
2199      {
2200         return -1;
2201      }
2202 }
2203
2204 /**
2205  * Get the DB pointer of an item
2206  *
2207  * @param sti The store item object
2208  * @return The DB pointer of item
2209  *
2210  * @ingroup Store
2211  */
2212 EAPI void *
2213 elm_store_dbsystem_db_get(const Elm_Store_Item *sti)
2214 {
2215    if (!EINA_MAGIC_CHECK(sti, ELM_STORE_ITEM_MAGIC)) return NULL;
2216
2217    const Elm_Store_DBsystem *std = (const Elm_Store_DBsystem *)sti->store;
2218    if (!EINA_MAGIC_CHECK(sti->store, ELM_STORE_MAGIC)) return NULL;
2219    if (!EINA_MAGIC_CHECK(std, ELM_STORE_DBSYSTEM_MAGIC)) return NULL;
2220    return std->p_db;
2221 }
2222
2223 /**
2224  * Set the DB pointer of an item
2225  *
2226  * @param sti The store item object
2227  * @parm p_db The DB pointer of item
2228  *
2229  * @ingroup Store
2230  */
2231 EAPI void
2232 elm_store_dbsystem_db_set(Elm_Store *store, void *p_db)
2233 {
2234    Elm_Store_DBsystem *std = (Elm_Store_DBsystem *)store;
2235    if (!EINA_MAGIC_CHECK(store, ELM_STORE_MAGIC)) return;
2236    if (!EINA_MAGIC_CHECK(std, ELM_STORE_DBSYSTEM_MAGIC)) return;
2237
2238    std->p_db = p_db;
2239
2240    if (store->list_th)
2241      {
2242         ecore_thread_cancel(store->list_th);
2243         store->list_th = NULL;
2244      }
2245    store->list_th = ecore_thread_feedback_run(_list_do, _list_update, _list_end, _list_cancel, store, EINA_TRUE);
2246 }
2247
2248 /**
2249  * Append the item to the genlist
2250  *
2251  * @param st The store object
2252  * @param info The store item info dbsystem object
2253  * @return The item of store
2254  *
2255  * @ingroup Store
2256  */
2257 EAPI Elm_Store_Item *
2258 elm_store_item_add(Elm_Store *st, Elm_Store_Item_Info *info)
2259 {
2260    EINA_SAFETY_ON_NULL_RETURN_VAL(st, NULL);
2261    if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return NULL;
2262    EINA_SAFETY_ON_NULL_RETURN_VAL(info, NULL);
2263    Elm_Store_Item *sti;
2264    Elm_Genlist_Item_Class *itc;
2265
2266    sti = calloc(1, sizeof(Elm_Store_Item));
2267    if (!sti) return NULL;
2268
2269    LKI(sti->lock);
2270    EINA_MAGIC_SET(sti, ELM_STORE_ITEM_MAGIC);
2271
2272    sti->store = st;
2273    sti->item_info = info;
2274    sti->fetched = EINA_FALSE;
2275
2276    itc = info->item_class;
2277    if (!itc) itc = &_store_item_class;
2278    else
2279      {
2280         itc->func.label_get = (GenlistItemLabelGetFunc)_item_label_get;
2281         itc->func.icon_get = (GenlistItemIconGetFunc)_item_icon_get;
2282         itc->func.state_get = NULL;
2283         itc->func.del = NULL;
2284      }
2285
2286    if (st->live)
2287      {
2288         if (sti->item_info->item_type == ELM_GENLIST_ITEM_GROUP)
2289           {
2290              _group_item_append(sti, itc);
2291           }
2292         else
2293           {
2294              _normal_item_append(sti, itc);
2295           }
2296         return sti;
2297      }
2298    else
2299      {
2300         return NULL;
2301      }
2302 }
2303
2304 /**
2305  * Realize the visible items to the screen
2306  *
2307  * @param st The store object
2308  *
2309  * @ingroup Store
2310  */
2311 EAPI void
2312 elm_store_visible_items_update(Elm_Store *st)
2313 {
2314    EINA_SAFETY_ON_NULL_RETURN(st);
2315    if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return;
2316
2317    Eina_List *realized_list = elm_genlist_realized_items_get(st->genlist);
2318    if(realized_list)
2319      {
2320         Eina_List *l;
2321         Elm_Genlist_Item *it;
2322         EINA_LIST_FOREACH(realized_list, l, it)
2323           {
2324              if(it)
2325                {
2326                   Elm_Store_Item *realized_sti = elm_genlist_item_data_get(it);
2327                   int index = elm_store_item_index_get(realized_sti);
2328                   if (index != -1)
2329                     {
2330                        if(realized_sti->fetched)
2331                          {
2332                             _item_unfetch(st, index);
2333                          }
2334                        _item_fetch(st, index);
2335                        if (realized_sti->data) elm_genlist_item_update(realized_sti->item);
2336                     }
2337                   else
2338                     {
2339                        return;
2340                     }
2341                }
2342           }
2343      }
2344 }
2345
2346 /**
2347  * Realize the item to the screen
2348  *
2349  * @param sti The store item object
2350  *
2351  * @ingroup Store
2352  */
2353 EAPI void
2354 elm_store_item_update(Elm_Store_Item *sti)
2355 {
2356    EINA_SAFETY_ON_NULL_RETURN(sti);
2357    if (!EINA_MAGIC_CHECK(sti, ELM_STORE_ITEM_MAGIC)) return;
2358    Elm_Store *st = sti->store;
2359
2360    int index = elm_store_item_index_get(sti);
2361    if (index != -1)
2362      {
2363         if ((st->start_fetch_index <= index) && (index <= (st->start_fetch_index + st->cache_max)))
2364           {
2365              if (sti->fetched)
2366                {
2367                   _item_unfetch(st, index);
2368                }
2369              _item_fetch(st, index);
2370
2371              if(st->end_fetch_index < (st->total_item_count-1))
2372                {
2373                   if( (st->end_fetch_index - st->cache_max) == st->start_fetch_index)
2374                     {
2375                        _item_unfetch(st, (st->total_item_count-1));
2376                     }
2377                   else
2378                     {
2379                        st->end_fetch_index = (st->total_item_count-1);
2380                     }
2381                }
2382              if(sti->data) elm_genlist_item_update(sti->item);
2383           }
2384      }
2385    else
2386      {
2387         return;
2388      }
2389 }
2390
2391 /**
2392  * Delete the item of genlist
2393  *
2394  * @param sti The store item object
2395  *
2396  * @ingroup Store
2397  */
2398 EAPI void
2399 elm_store_item_del(Elm_Store_Item *sti)
2400 {
2401    EINA_SAFETY_ON_NULL_RETURN(sti);
2402    if (!EINA_MAGIC_CHECK(sti, ELM_STORE_ITEM_MAGIC)) return;
2403    Elm_Store *st = sti->store;
2404
2405    Eina_List *l;
2406    Eina_List*l_next;
2407    Eina_List *header_list;
2408
2409    if (st->live)
2410      {
2411         EINA_LIST_FOREACH_SAFE(st->header_items, l, l_next, header_list)
2412           {
2413              if (header_list)
2414                {
2415                   Elm_Store_Item *header_item = eina_list_nth(header_list, 0);
2416                   if(header_item && header_item->item_info && sti->item_info)
2417                     {
2418
2419                        if (header_item->item_info->group_index == sti->item_info->group_index)
2420                          {
2421                             Eina_Bool removed = EINA_FALSE;
2422                             Eina_List *in_l;
2423                             Eina_List *in_l_next;
2424                             Elm_Store_Item *remove_sti;
2425                             EINA_LIST_FOREACH_SAFE(header_list, in_l, in_l_next, remove_sti)
2426                               {
2427                                  if(remove_sti)
2428                                    {
2429                                       if (removed == EINA_TRUE)
2430                                         {
2431                                            remove_sti->item_info->index--;
2432                                         }
2433                                       else
2434                                         {
2435                                            if (remove_sti->item_info->index == sti->item_info->index)
2436                                              {
2437                                                 if (remove_sti->fetched)
2438                                                   {
2439                                                      int index = elm_store_item_index_get(remove_sti);
2440                                                      if (index != -1)
2441                                                        {
2442                                                           _item_unfetch(st, index);
2443                                                        }
2444                                                      else
2445                                                        {
2446                                                           return;
2447                                                        }
2448                                                   }
2449                                                 if (st->cb.item_free.func)
2450                                                   {
2451                                                      st->cb.item_free.func(st->cb.item_free.data, remove_sti->item_info);
2452                                                      remove_sti->item_info = NULL;
2453                                                   }
2454
2455                                                 if (eina_list_count(header_list) == 1)
2456                                                   {
2457                                                      st->header_items = eina_list_remove(st->header_items, header_list);
2458                                                      header_list = eina_list_free(header_list);
2459                                                      st->total_item_count--;
2460                                                      LKD(remove_sti->lock);
2461                                                      elm_genlist_item_del(remove_sti->item);
2462                                                      free(remove_sti);
2463                                                      return;
2464                                                   }
2465                                                 else
2466                                                   {
2467                                                      header_list = eina_list_remove(header_list, remove_sti);
2468                                                      st->total_item_count--;
2469                                                      LKD(remove_sti->lock);
2470                                                      elm_genlist_item_del(remove_sti->item);
2471                                                      free(remove_sti);
2472                                                   }
2473
2474                                                 if (eina_list_count(header_list) == 1)
2475                                                   {
2476                                                      Elm_Store_Item *t_sti = eina_list_nth(header_list, 0);
2477                                                      if(t_sti && t_sti->item_info)
2478                                                        {
2479                                                           if (t_sti->item_info->item_type == ELM_GENLIST_ITEM_GROUP)
2480                                                             {
2481                                                                if (t_sti->fetched)
2482                                                                  {
2483                                                                     int index = elm_store_item_index_get(t_sti);
2484                                                                     if (index != -1)
2485                                                                       {
2486                                                                          _item_unfetch(st, index);
2487                                                                       }
2488                                                                     else
2489                                                                       {
2490                                                                          return;
2491                                                                       }
2492                                                                  }
2493                                                                if (st->cb.item_free.func)
2494                                                                  {
2495                                                                     st->cb.item_free.func(st->cb.item_free.data, t_sti->item_info);
2496                                                                     t_sti->item_info = NULL;
2497                                                                  }
2498                                                                st->header_items = eina_list_remove(st->header_items, header_list);
2499                                                                header_list = eina_list_free(header_list);
2500                                                                st->total_item_count--;
2501                                                                LKD(t_sti->lock);
2502                                                                elm_genlist_item_del(t_sti->item);
2503                                                                free(t_sti);
2504                                                             }
2505                                                        }
2506                                                   }
2507                                                 removed = EINA_TRUE;
2508                                              }
2509                                         }
2510                                    }
2511                               }
2512                          }
2513                     }
2514                }
2515           }
2516      }
2517 }
2518
2519 // TODO: END -DBsystem store
2520