[elm] add shots feature from upstream
[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    EINA_SAFETY_ON_NULL_RETURN(data);
1409    EINA_SAFETY_ON_NULL_RETURN(th);
1410    Elm_Store *st = data;
1411
1412    if (th == st->list_th)
1413      {
1414         ecore_thread_cancel(st->list_th);
1415         st->list_th = NULL;
1416      }
1417 }
1418
1419 static void
1420 _list_cancel(void *data, Ecore_Thread *th)
1421 {
1422    EINA_SAFETY_ON_NULL_RETURN(data);
1423    EINA_SAFETY_ON_NULL_RETURN(th);
1424    Elm_Store *st = data;
1425
1426    if (th == st->list_th)
1427      {
1428         ecore_thread_cancel(st->list_th);
1429         st->list_th = NULL;
1430      }
1431 }
1432
1433 static void
1434 _item_select_cb(void *data __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info)
1435 {
1436    EINA_SAFETY_ON_NULL_RETURN(event_info);
1437
1438    const Elm_Genlist_Item *it = (Elm_Genlist_Item *)event_info;
1439    Elm_Store_Item *sti = elm_genlist_item_data_get(it);
1440    if (!EINA_MAGIC_CHECK(sti, ELM_STORE_ITEM_MAGIC)) return;
1441
1442    if (sti->store->cb.item_select.func)
1443      {
1444         sti->store->cb.item_select.func(sti->store->cb.item_select.data, sti);
1445      }
1446 }
1447
1448 static void
1449 _group_item_append(Elm_Store_Item *sti, Elm_Genlist_Item_Class *itc)
1450 {
1451    EINA_SAFETY_ON_NULL_RETURN(sti);
1452    if (!EINA_MAGIC_CHECK(sti, ELM_STORE_ITEM_MAGIC)) return;
1453    Elm_Store *st = sti->store;
1454    if (st->live)
1455      {
1456         if (st->header_items)
1457           {
1458              Eina_Bool header_add = EINA_TRUE;
1459              Eina_List *l;
1460              Eina_List *l_next;
1461              Eina_List *header_list;
1462
1463              EINA_LIST_FOREACH_SAFE(st->header_items, l, l_next, header_list)
1464                {
1465                   if(header_list)
1466                     {
1467                        Elm_Store_Item *item = eina_list_nth(header_list, 0);
1468                        if(item && item->item_info)
1469                          {
1470                             if (item->item_info->group_index == sti->item_info->group_index)
1471                               {
1472                                  header_add = EINA_FALSE;
1473                                  break;
1474                               }
1475                          }
1476                     }
1477                }
1478              if (header_add)
1479                {
1480                   Eina_List *new_header_list = NULL;
1481                   sti->item_info->index = 0;
1482                   new_header_list = eina_list_append(new_header_list, sti);
1483                   st->total_item_count++;
1484
1485                   Eina_Bool last_header = EINA_TRUE;
1486                   Eina_List *l;
1487                   Eina_List *l_next;
1488                   Eina_List *header_list;
1489
1490                   EINA_LIST_FOREACH_SAFE(st->header_items, l, l_next, header_list)
1491                     {
1492                        if (header_list)
1493                          {
1494                             Elm_Store_Item *group_sti = eina_list_nth(header_list, 0);
1495                             if(group_sti && group_sti->item_info)
1496                               {
1497                                  if(group_sti->item_info->item_type == ELM_GENLIST_ITEM_GROUP)
1498                                    {
1499                                       int sort;
1500                                       if (st->cb.item_sort.func)
1501                                         {
1502                                            sort = st->cb.item_sort.func(st->cb.item_sort.data, sti->item_info, group_sti->item_info);
1503
1504                                            if(sort == ELM_STORE_ITEM_SORT_LOW)
1505                                              {
1506                                                 st->header_items = eina_list_prepend_relative(st->header_items, new_header_list, header_list);
1507                                                 sti->item = elm_genlist_item_insert_before(st->genlist,
1508                                                                                            itc,
1509                                                                                            sti,
1510                                                                                            NULL,
1511                                                                                            group_sti->item,
1512                                                                                            ELM_GENLIST_ITEM_GROUP,
1513                                                                                            NULL,
1514                                                                                            NULL);
1515                                                 last_header = EINA_FALSE;
1516                                                 break;
1517                                              }
1518                                         }
1519                                       else
1520                                         {
1521                                            break;
1522                                         }
1523                                    }
1524                               }
1525                          }
1526                     }
1527                   if (last_header)
1528                     {
1529                        st->header_items = eina_list_append(st->header_items, new_header_list);
1530                        sti->item = elm_genlist_item_append(st->genlist,
1531                                                            itc,
1532                                                            sti,
1533                                                            NULL,
1534                                                            ELM_GENLIST_ITEM_GROUP,
1535                                                            NULL,
1536                                                            NULL);
1537                     }
1538                   elm_store_item_update(sti);
1539                }
1540           }
1541         else
1542           {
1543              Eina_List *header_list = NULL;
1544              sti->item_info->index = 0;
1545              header_list = eina_list_append(header_list, sti);
1546              st->total_item_count++;
1547              st->header_items = eina_list_append(st->header_items, header_list);
1548              sti->item = elm_genlist_item_append(st->genlist,
1549                                                  itc,
1550                                                  sti,
1551                                                  NULL,
1552                                                  ELM_GENLIST_ITEM_GROUP,
1553                                                  NULL,
1554                                                  NULL);
1555              elm_store_item_update(sti);
1556           }
1557      }
1558 }
1559
1560 static void
1561 _normal_item_append(Elm_Store_Item *sti, Elm_Genlist_Item_Class *itc)
1562 {
1563    EINA_SAFETY_ON_NULL_RETURN(sti);
1564    if (!EINA_MAGIC_CHECK(sti, ELM_STORE_ITEM_MAGIC)) return;
1565    Elm_Store *st = sti->store;
1566    if (st->live)
1567      {
1568         if (sti->item_info->rec_item == EINA_TRUE)
1569           {
1570              if (sti->item_info->group_index == sti->item_info->pre_group_index)
1571                {
1572                   Eina_List *l;
1573                   Eina_List *l_next;
1574                   Eina_List *header_list;
1575
1576                   EINA_LIST_FOREACH_SAFE(st->header_items, l, l_next, header_list)
1577                     {
1578                        if(header_list)
1579                          {
1580                             Elm_Store_Item *header_item = eina_list_nth(header_list, 0);
1581                             if(header_item && header_item->item_info)
1582                               {
1583                                  if (header_item->item_info->group_index == sti->item_info->group_index)
1584                                    {
1585                                       Eina_List *in_l;
1586                                       Eina_List *in_l_next;
1587                                       Elm_Store_Item *item;
1588
1589                                       EINA_LIST_FOREACH_SAFE(header_list, in_l, in_l_next, item)
1590                                         {
1591                                            if(item)
1592                                              {
1593                                                 int sort;
1594                                                 if (st->cb.item_sort.func)
1595                                                   {
1596                                                      sort = st->cb.item_sort.func(st->cb.item_sort.data, sti->item_info, item->item_info);
1597
1598                                                      if(sort == ELM_STORE_ITEM_SORT_SAME)
1599                                                        {
1600                                                           elm_store_item_update(item);
1601                                                        }
1602                                                   }
1603                                                 else
1604                                                   {
1605                                                      break;
1606                                                   }
1607
1608                                              }
1609                                         }
1610                                    }
1611                               }
1612                          }
1613                     }
1614                }
1615              else
1616                {
1617                   Eina_List *l;
1618                   Eina_List *l_next;
1619                   Eina_List *header_list;
1620
1621                   EINA_LIST_FOREACH_SAFE(st->header_items, l, l_next, header_list)
1622                     {
1623                        if(header_list)
1624                          {
1625                             Elm_Store_Item *header_item = eina_list_nth(header_list, 0);
1626                             if(header_item && header_item->item_info)
1627                               {
1628                                  if (header_item->item_info->group_index == sti->item_info->pre_group_index)
1629                                    {
1630                                       Eina_Bool removed = EINA_FALSE;
1631                                       Eina_List *in_l;
1632                                       Eina_List *in_l_next;
1633                                       Elm_Store_Item *remove_item;
1634
1635                                       EINA_LIST_FOREACH_SAFE(header_list, in_l, in_l_next, remove_item)
1636                                         {
1637                                            if(remove_item)
1638                                              {
1639                                                 if (removed == EINA_TRUE)
1640                                                   {
1641                                                      remove_item->item_info->index--;
1642                                                   }
1643                                                 else
1644                                                   {
1645                                                      int sort;
1646                                                      if (st->cb.item_sort.func)
1647                                                        {
1648                                                           sort = st->cb.item_sort.func(st->cb.item_sort.data, sti->item_info, remove_item->item_info);
1649
1650                                                           if(sort == ELM_STORE_ITEM_SORT_SAME)
1651                                                             {
1652                                                                if (remove_item->fetched)
1653                                                                  {
1654                                                                     int index = elm_store_item_index_get(remove_item);
1655                                                                     if (index != -1)
1656                                                                       {
1657                                                                          _item_unfetch(st, index);
1658                                                                       }
1659                                                                     else
1660                                                                       {
1661                                                                          return;
1662                                                                       }
1663                                                                  }
1664                                                                if (st->cb.item_free.func)
1665                                                                  {
1666                                                                     st->cb.item_free.func(st->cb.item_free.data, remove_item->item_info);
1667                                                                     remove_item->item_info = NULL;
1668                                                                  }
1669
1670                                                                Eina_List *temp_header_list = header_list;
1671                                                                header_list = eina_list_remove(header_list, remove_item);
1672                                                                st->total_item_count--;
1673                                                                LKD(remove_item->lock);
1674                                                                elm_genlist_item_del(remove_item->item);
1675                                                                free(remove_item);
1676
1677                                                                if (eina_list_count(header_list) == 0)
1678                                                                  {
1679                                                                     st->header_items = eina_list_remove(st->header_items, temp_header_list);
1680                                                                     header_list = eina_list_free(header_list);
1681                                                                  }
1682                                                                else if(eina_list_count(header_list) == 1)
1683                                                                  {
1684                                                                     Elm_Store_Item *temp_sti = eina_list_nth(header_list, 0);
1685                                                                     if(temp_sti && temp_sti->item_info)
1686                                                                       {
1687                                                                          if (temp_sti->item_info->item_type == ELM_GENLIST_ITEM_GROUP)
1688                                                                            {
1689                                                                               if (temp_sti->fetched)
1690                                                                                 {
1691                                                                                    int index = elm_store_item_index_get(temp_sti);
1692                                                                                    if (index != -1)
1693                                                                                      {
1694                                                                                         _item_unfetch(st, index);
1695                                                                                      }
1696                                                                                    else
1697                                                                                      {
1698                                                                                         return;
1699                                                                                      }
1700                                                                                 }
1701
1702                                                                               if (st->cb.item_free.func)
1703                                                                                 {
1704                                                                                    st->cb.item_free.func(st->cb.item_free.data, temp_sti->item_info);
1705                                                                                    temp_sti->item_info = NULL;
1706                                                                                 }
1707
1708                                                                               header_list = eina_list_remove(header_list, temp_sti);
1709                                                                               st->total_item_count--;
1710                                                                               LKD(temp_sti->lock);
1711                                                                               elm_genlist_item_del(temp_sti->item);
1712                                                                               free(temp_sti);
1713                                                                               st->header_items = eina_list_remove(st->header_items, temp_header_list);
1714                                                                               header_list = eina_list_free(header_list);
1715                                                                            }
1716                                                                       }
1717                                                                  }
1718                                                                temp_header_list = eina_list_free(temp_header_list);
1719                                                                removed = EINA_TRUE;
1720                                                             }
1721                                                        }
1722                                                      else
1723                                                        {
1724                                                           break;
1725                                                        }
1726                                                   }
1727                                              }
1728                                         }
1729                                    }
1730                                  else if (header_item->item_info->group_index == sti->item_info->group_index)
1731                                    {
1732                                       Eina_Bool last_add = EINA_TRUE;
1733                                       Eina_List *in_l;
1734                                       Eina_List *in_l_next;
1735                                       Elm_Store_Item *comp_item;
1736
1737                                       EINA_LIST_FOREACH_SAFE(header_list, in_l, in_l_next, comp_item)
1738                                         {
1739                                            if(comp_item)
1740                                              {
1741                                                 if(last_add == EINA_FALSE)
1742                                                   {
1743                                                      comp_item->item_info->index++;
1744                                                   }
1745                                                 else
1746                                                   {
1747                                                      int sort;
1748                                                      if (st->cb.item_sort.func)
1749                                                        {
1750                                                           sort = st->cb.item_sort.func(st->cb.item_sort.data, sti->item_info, comp_item->item_info);
1751
1752                                                           if(sort == ELM_STORE_ITEM_SORT_LOW)
1753                                                             {
1754                                                                sti->item_info->index = comp_item->item_info->index;
1755                                                                comp_item->item_info->index++;
1756                                                                header_list = eina_list_prepend_relative(header_list, sti, comp_item);
1757                                                                st->total_item_count++;
1758                                                                sti->item = elm_genlist_item_insert_before(st->genlist,
1759                                                                                                           itc,
1760                                                                                                           sti,
1761                                                                                                           header_item->item,
1762                                                                                                           comp_item->item,
1763                                                                                                           ELM_GENLIST_ITEM_NONE,
1764                                                                                                           (Evas_Smart_Cb)sti->store->cb.item_select.func,
1765                                                                                                           (void *)sti->store->cb.item_select.data);
1766                                                                elm_store_item_update(sti);
1767                                                                last_add = EINA_FALSE;
1768                                                             }
1769                                                        }
1770                                                      else
1771                                                        {
1772                                                           Elm_Store_Item *last_sti = eina_list_nth(header_list, eina_list_count(header_list) - 1);
1773                                                           sti->item_info->index = eina_list_count(header_list);
1774                                                           header_list = eina_list_append(header_list, sti);
1775                                                           st->total_item_count++;
1776                                                           sti->item = elm_genlist_item_insert_after(st->genlist,
1777                                                                                                     itc,
1778                                                                                                     sti,
1779                                                                                                     header_item->item,
1780                                                                                                     last_sti->item,
1781                                                                                                     ELM_GENLIST_ITEM_NONE,
1782                                                                                                     (Evas_Smart_Cb)sti->store->cb.item_select.func,
1783                                                                                                     (void *)sti->store->cb.item_select.data);
1784                                                           elm_store_item_update(sti);
1785                                                           last_add = EINA_FALSE;
1786                                                           break;
1787                                                        }
1788                                                   }
1789                                              }
1790                                         }
1791                                       if(last_add)
1792                                         {
1793                                            Elm_Store_Item *last_sti = eina_list_nth(header_list, eina_list_count(header_list) - 1);
1794                                            sti->item_info->index = eina_list_count(header_list);
1795                                            header_list = eina_list_append(header_list, sti);
1796                                            st->total_item_count++;
1797                                            sti->item = elm_genlist_item_insert_after(st->genlist,
1798                                                                                      itc,
1799                                                                                      sti,
1800                                                                                      header_item->item,
1801                                                                                      last_sti->item,
1802                                                                                      ELM_GENLIST_ITEM_NONE,
1803                                                                                      (Evas_Smart_Cb)sti->store->cb.item_select.func,
1804                                                                                      (void *)sti->store->cb.item_select.data);
1805                                            elm_store_item_update(sti);
1806                                         }
1807                                    }
1808                               }
1809                          }
1810                     }
1811                }
1812           }
1813         else
1814           {
1815              if (st->header_items)
1816                {
1817                   Eina_Bool normal_add = EINA_TRUE;
1818                   Eina_List *l;
1819                   Eina_List *l_next;
1820                   Eina_List *header_list;
1821
1822                   EINA_LIST_FOREACH_SAFE(st->header_items, l, l_next, header_list)
1823                     {
1824                        if (header_list)
1825                          {
1826                             Elm_Store_Item *header_item = eina_list_nth(header_list, 0);
1827
1828                             if(header_item && header_item->item_info)
1829                               {
1830                                  if (header_item->item_info->group_index == sti->item_info->group_index)
1831                                    {
1832                                       Eina_List *in_l;
1833                                       Eina_List *in_l_next;
1834                                       Elm_Store_Item *comp_item;
1835
1836                                       EINA_LIST_FOREACH_SAFE(header_list, in_l, in_l_next, comp_item)
1837                                         {
1838                                            if (comp_item )
1839                                              {
1840                                                 if(normal_add == EINA_FALSE)
1841                                                   {
1842                                                      comp_item->item_info->index++;
1843                                                   }
1844                                                 else
1845                                                   {
1846                                                      int sort;
1847                                                      if (st->cb.item_sort.func)
1848                                                        {
1849                                                           sort = st->cb.item_sort.func(st->cb.item_sort.data, sti->item_info, comp_item->item_info);
1850
1851                                                           if(sort == ELM_STORE_ITEM_SORT_LOW)
1852                                                             {
1853                                                                sti->item_info->index = comp_item->item_info->index;
1854                                                                comp_item->item_info->index++;
1855                                                                header_list = eina_list_prepend_relative(header_list, sti, comp_item);
1856                                                                st->total_item_count++;
1857                                                                sti->item = elm_genlist_item_insert_before(st->genlist,
1858                                                                                                           itc,
1859                                                                                                           sti,
1860                                                                                                           header_item->item,
1861                                                                                                           comp_item->item,
1862                                                                                                           ELM_GENLIST_ITEM_NONE,
1863                                                                                                           (Evas_Smart_Cb)sti->store->cb.item_select.func,
1864                                                                                                           (void *)sti->store->cb.item_select.data);
1865                                                                normal_add = EINA_FALSE;
1866                                                                elm_store_item_update(sti);
1867                                                             }
1868                                                        }
1869                                                      else
1870                                                        {
1871                                                           Elm_Store_Item *last_sti = eina_list_nth(header_list, eina_list_count(header_list) - 1);
1872                                                           sti->item_info->index = eina_list_count(header_list);
1873                                                           header_list = eina_list_append(header_list, sti);
1874                                                           st->total_item_count++;
1875                                                           sti->item = elm_genlist_item_insert_after(st->genlist,
1876                                                                                                     itc,
1877                                                                                                     sti,
1878                                                                                                     header_item->item,
1879                                                                                                     last_sti->item,
1880                                                                                                     ELM_GENLIST_ITEM_NONE,
1881                                                                                                     (Evas_Smart_Cb)sti->store->cb.item_select.func,
1882                                                                                                     (void *)sti->store->cb.item_select.data);
1883                                                           normal_add = EINA_FALSE;
1884                                                           elm_store_item_update(sti);
1885                                                           break;
1886                                                        }
1887                                                   }
1888                                              }
1889                                         }
1890                                       if(normal_add)
1891                                         {
1892                                            Elm_Store_Item *last_sti = eina_list_nth(header_list, eina_list_count(header_list) - 1);
1893                                            sti->item_info->index = eina_list_count(header_list);
1894                                            header_list = eina_list_append(header_list, sti);
1895                                            st->total_item_count++;
1896                                            sti->item = elm_genlist_item_insert_after(st->genlist,
1897                                                                                      itc,
1898                                                                                      sti,
1899                                                                                      header_item->item,
1900                                                                                      last_sti->item,
1901                                                                                      ELM_GENLIST_ITEM_NONE,
1902                                                                                      (Evas_Smart_Cb)sti->store->cb.item_select.func,
1903                                                                                      (void *)sti->store->cb.item_select.data);
1904                                            normal_add = EINA_FALSE;
1905                                            elm_store_item_update(sti);
1906                                         }
1907                                       if(normal_add == EINA_FALSE)
1908                                         {
1909                                            break;
1910                                         }
1911                                    }
1912                               }
1913                          }
1914                     }
1915                   if (normal_add)
1916                     {
1917                        Eina_List *new_header_list = NULL;
1918                        sti->item_info->index = 0;
1919                        new_header_list = eina_list_append(new_header_list, sti);
1920                        st->total_item_count++;
1921                        st->header_items = eina_list_append(st->header_items, new_header_list);
1922                        sti->item = elm_genlist_item_append(st->genlist,
1923                                                            itc,
1924                                                            sti,
1925                                                            NULL,
1926                                                            ELM_GENLIST_ITEM_NONE,
1927                                                            (Evas_Smart_Cb)sti->store->cb.item_select.func,
1928                                                            (void *)sti->store->cb.item_select.data);
1929                        elm_store_item_update(sti);
1930                     }
1931                }
1932              else
1933                {
1934                   if (st->live)
1935                     {
1936                        Eina_List *new_header_list = NULL;
1937                        sti->item_info->index = 0;
1938                        new_header_list = eina_list_append(new_header_list, sti);
1939                        st->total_item_count++;
1940                        st->header_items = eina_list_append(st->header_items, new_header_list);
1941                        sti->item = elm_genlist_item_append(st->genlist,
1942                                                            itc,
1943                                                            sti,
1944                                                            NULL,
1945                                                            ELM_GENLIST_ITEM_NONE,
1946                                                            (Evas_Smart_Cb)sti->store->cb.item_select.func,
1947                                                            (void *)sti->store->cb.item_select.data);
1948                        elm_store_item_update(sti);
1949                     }
1950                }
1951           }
1952      }
1953 }
1954
1955 static void
1956 _item_free(Elm_Store_Item *sti)
1957 {
1958    if (!EINA_MAGIC_CHECK(sti, ELM_STORE_ITEM_MAGIC)) return;
1959    elm_store_item_del(sti);
1960 }
1961
1962 static void
1963 _store_free(Elm_Store *st)
1964 {
1965    if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return;
1966
1967    Elm_Store_DBsystem *std = (Elm_Store_DBsystem *)st;
1968    eina_stringshare_del(std->p_db);
1969    elm_store_free(st);
1970 }
1971
1972 /**
1973  * Add a new dbsystem Store object
1974  *
1975  * @return The new object or NULL if it cannot be created
1976  *
1977  * @ingroup Store
1978  */
1979 EAPI Elm_Store *
1980 elm_store_dbsystem_new(void)
1981 {
1982    Elm_Store_DBsystem *std = _store_new(Elm_Store_DBsystem);
1983    EINA_SAFETY_ON_NULL_RETURN_VAL(std, NULL);
1984
1985    EINA_MAGIC_SET(std, ELM_STORE_DBSYSTEM_MAGIC);
1986    std->base.free = _store_free;
1987    std->base.item.free = _item_free;
1988    return &std->base;
1989 }
1990
1991 /**
1992  * Sets the item count of a store
1993  *
1994  * @param st The store object
1995  * @param count The item count of an store
1996  *
1997  * @ingroup Store
1998  */
1999 EAPI void
2000 elm_store_item_count_set(Elm_Store *st, int count)
2001 {
2002    EINA_SAFETY_ON_NULL_RETURN(st);
2003    if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return;
2004
2005    st->item_count = count;
2006    if (count > 0)
2007      {
2008         st->multi_load = EINA_TRUE;
2009      }
2010    else
2011      {
2012         st->multi_load = EINA_FALSE;
2013      }
2014 }
2015
2016
2017 /**
2018  * Set the select func that select the state of a list item whether true or false
2019  *
2020  * @param st The store object
2021  * @param func The select cb function of an store
2022  * @param data The new data pointer to set
2023  *
2024  * @ingroup Store
2025  */
2026 EAPI void
2027 elm_store_item_select_func_set(Elm_Store *st, Elm_Store_Item_Select_Cb func, const void *data)
2028 {
2029    EINA_SAFETY_ON_NULL_RETURN(st);
2030    if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return;
2031
2032    st->cb.item_select.func = func;
2033    st->cb.item_select.data = (void *)data;
2034 }
2035
2036 /**
2037  * Sets the sort func that sort the item with a next in the list
2038  *
2039  * @param st The store object
2040  * @param func The sort cb function of an store
2041  * @param data The new data pointer to set
2042  *
2043  * @ingroup Store
2044  */
2045 EAPI void
2046 elm_store_item_sort_func_set(Elm_Store *st, Elm_Store_Item_Sort_Cb func, const void *data)
2047 {
2048    EINA_SAFETY_ON_NULL_RETURN(st);
2049    if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return;
2050
2051    st->cb.item_sort.func = func;
2052    st->cb.item_sort.data = (void *)data;
2053 }
2054
2055 /**
2056  * Set the store item free func
2057  *
2058  * @param st The store object
2059  * @param func The free cb function of an store
2060  * @param data The new data pointer to set
2061  *
2062  * @ingroup Store
2063  */
2064 EAPI void
2065 elm_store_item_free_func_set(Elm_Store *st, Elm_Store_Item_Free_Cb func, const void *data)
2066 {
2067    EINA_SAFETY_ON_NULL_RETURN(st);
2068    if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return;
2069
2070    st->cb.item_free.func = func;
2071    st->cb.item_free.data = (void *)data;
2072 }
2073
2074 /**
2075  * Get the item index that included header items
2076  *
2077  * @param sti The store item object
2078  * @return The item index in genlist
2079  *
2080  * @ingroup Store
2081  */
2082 EAPI int
2083 elm_store_item_index_get(const Elm_Store_Item *sti)
2084 {
2085    EINA_SAFETY_ON_NULL_RETURN_VAL(sti, -1);
2086    if (!EINA_MAGIC_CHECK(sti, ELM_STORE_ITEM_MAGIC)) return -1;
2087    Elm_Store *st = sti->store;
2088
2089    if (st->live)
2090      {
2091         int index = 0;
2092         Eina_List *l;
2093         Eina_List *l_next;
2094         Eina_List *header_list;
2095
2096         EINA_LIST_FOREACH_SAFE(st->header_items, l, l_next, header_list)
2097           {
2098              if (header_list)
2099                {
2100                   Elm_Store_Item *temp_sti = eina_list_nth(header_list, 0);
2101                   if(temp_sti && temp_sti->item_info && sti->item_info)
2102                     {
2103                        if (sti->item_info->group_index == temp_sti->item_info->group_index)
2104                          {
2105                             Eina_List *in_l;
2106                             Eina_List *in_l_next;
2107                             Elm_Store_Item *comp_item;
2108
2109                             EINA_LIST_FOREACH_SAFE(header_list, in_l, in_l_next, comp_item)
2110                               {
2111                                  if(comp_item)
2112                                    {
2113                                       if (comp_item->item_info->index == sti->item_info->index)
2114                                         {
2115                                            return index;
2116                                         }
2117                                       else
2118                                         {
2119                                            index++;
2120                                         }
2121                                    }
2122                               }
2123                          }
2124                        else
2125                          {
2126                             index = index + eina_list_count(header_list);
2127                          }
2128                     }
2129                }
2130           }
2131         return -1;
2132      }
2133    else
2134      {
2135         return -1;
2136      }
2137 }
2138
2139 /**
2140  * Get the item index of real data that don't included header items
2141  *
2142  * @param sti The store item object
2143  * @return The real item index
2144  *
2145  * @ingroup Store
2146  */
2147 EAPI int
2148 elm_store_item_data_index_get(const Elm_Store_Item *sti)
2149 {
2150    EINA_SAFETY_ON_NULL_RETURN_VAL(sti, -1);
2151    if (!EINA_MAGIC_CHECK(sti, ELM_STORE_ITEM_MAGIC)) return -1;
2152    Elm_Store *st = sti->store;
2153
2154    if (st->live)
2155      {
2156         if (sti->item_info->item_type == ELM_GENLIST_ITEM_NONE)
2157           {
2158              int index = 0;
2159              int group_item_count = 0;
2160              Eina_List *l;
2161              Eina_List *l_next;
2162              Eina_List *header_list;
2163
2164              EINA_LIST_FOREACH_SAFE(st->header_items, l, l_next, header_list)
2165                {
2166                   if (header_list)
2167                     {
2168                        Elm_Store_Item *temp_sti = eina_list_nth(header_list, 0);
2169                        if(temp_sti && temp_sti->item_info && sti->item_info)
2170                          {
2171
2172                             if(temp_sti->item_info->item_type == ELM_GENLIST_ITEM_GROUP)
2173                               {
2174                                  group_item_count++;
2175                               }
2176
2177                             if (temp_sti->item_info->group_index == sti->item_info->group_index)
2178                               {
2179                                  Eina_List *in_l;
2180                                  Eina_List *in_l_next;
2181                                  Elm_Store_Item *comp_item;
2182
2183                                  EINA_LIST_FOREACH_SAFE(header_list, in_l, in_l_next, comp_item)
2184                                    {
2185                                       if(comp_item)
2186                                         {
2187                                            if (comp_item->item_info->index == sti->item_info->index)
2188                                              {
2189                                                 return (index - group_item_count);
2190                                              }
2191                                            else
2192                                              {
2193                                                 index++;
2194                                              }
2195                                         }
2196                                    }
2197                               }
2198                          }
2199                        else
2200                          {
2201                             index = index + eina_list_count(header_list);
2202                          }
2203                     }
2204                }
2205           }
2206         return -1;
2207      }
2208    else
2209      {
2210         return -1;
2211      }
2212 }
2213
2214 /**
2215  * Get the DB pointer of an item
2216  *
2217  * @param sti The store item object
2218  * @return The DB pointer of item
2219  *
2220  * @ingroup Store
2221  */
2222 EAPI void *
2223 elm_store_dbsystem_db_get(const Elm_Store_Item *sti)
2224 {
2225    if (!EINA_MAGIC_CHECK(sti, ELM_STORE_ITEM_MAGIC)) return NULL;
2226
2227    const Elm_Store_DBsystem *std = (const Elm_Store_DBsystem *)sti->store;
2228    if (!EINA_MAGIC_CHECK(sti->store, ELM_STORE_MAGIC)) return NULL;
2229    if (!EINA_MAGIC_CHECK(std, ELM_STORE_DBSYSTEM_MAGIC)) return NULL;
2230    return std->p_db;
2231 }
2232
2233 /**
2234  * Set the DB pointer of an item
2235  *
2236  * @param sti The store item object
2237  * @parm p_db The DB pointer of item
2238  *
2239  * @ingroup Store
2240  */
2241 EAPI void
2242 elm_store_dbsystem_db_set(Elm_Store *store, void *p_db)
2243 {
2244    Elm_Store_DBsystem *std = (Elm_Store_DBsystem *)store;
2245    if (!EINA_MAGIC_CHECK(store, ELM_STORE_MAGIC)) return;
2246    if (!EINA_MAGIC_CHECK(std, ELM_STORE_DBSYSTEM_MAGIC)) return;
2247
2248    std->p_db = p_db;
2249
2250    if (store->list_th)
2251      {
2252         ecore_thread_cancel(store->list_th);
2253         store->list_th = NULL;
2254      }
2255    store->list_th = ecore_thread_feedback_run(_list_do, _list_update, _list_end, _list_cancel, store, EINA_TRUE);
2256 }
2257
2258 /**
2259  * Append the item to the genlist
2260  *
2261  * @param st The store object
2262  * @param info The store item info dbsystem object
2263  * @return The item of store
2264  *
2265  * @ingroup Store
2266  */
2267 EAPI Elm_Store_Item *
2268 elm_store_item_add(Elm_Store *st, Elm_Store_Item_Info *info)
2269 {
2270    EINA_SAFETY_ON_NULL_RETURN_VAL(st, NULL);
2271    if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return NULL;
2272    EINA_SAFETY_ON_NULL_RETURN_VAL(info, NULL);
2273    Elm_Store_Item *sti;
2274    Elm_Genlist_Item_Class *itc;
2275
2276    sti = calloc(1, sizeof(Elm_Store_Item));
2277    if (!sti) return NULL;
2278
2279    LKI(sti->lock);
2280    EINA_MAGIC_SET(sti, ELM_STORE_ITEM_MAGIC);
2281
2282    sti->store = st;
2283    sti->item_info = info;
2284    sti->fetched = EINA_FALSE;
2285
2286    itc = info->item_class;
2287    if (!itc) itc = &_store_item_class;
2288    else
2289      {
2290         itc->func.label_get = (GenlistItemLabelGetFunc)_item_label_get;
2291         itc->func.icon_get = (GenlistItemIconGetFunc)_item_icon_get;
2292         itc->func.state_get = NULL;
2293         itc->func.del = NULL;
2294      }
2295
2296    if (st->live)
2297      {
2298         if (sti->item_info->item_type == ELM_GENLIST_ITEM_GROUP)
2299           {
2300              _group_item_append(sti, itc);
2301           }
2302         else
2303           {
2304              _normal_item_append(sti, itc);
2305           }
2306         return sti;
2307      }
2308    else
2309      {
2310         return NULL;
2311      }
2312 }
2313
2314 /**
2315  * Realize the visible items to the screen
2316  *
2317  * @param st The store object
2318  *
2319  * @ingroup Store
2320  */
2321 EAPI void
2322 elm_store_visible_items_update(Elm_Store *st)
2323 {
2324    EINA_SAFETY_ON_NULL_RETURN(st);
2325    if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return;
2326
2327    Eina_List *realized_list = elm_genlist_realized_items_get(st->genlist);
2328    if(realized_list)
2329      {
2330         Eina_List *l;
2331         Elm_Genlist_Item *it;
2332         EINA_LIST_FOREACH(realized_list, l, it)
2333           {
2334              if(it)
2335                {
2336                   Elm_Store_Item *realized_sti = elm_genlist_item_data_get(it);
2337                   int index = elm_store_item_index_get(realized_sti);
2338                   if (index != -1)
2339                     {
2340                        if(realized_sti->fetched)
2341                          {
2342                             _item_unfetch(st, index);
2343                          }
2344                        _item_fetch(st, index);
2345                        if (realized_sti->data) elm_genlist_item_update(realized_sti->item);
2346                     }
2347                   else
2348                     {
2349                        return;
2350                     }
2351                }
2352           }
2353      }
2354 }
2355
2356 /**
2357  * Realize the item to the screen
2358  *
2359  * @param sti The store item object
2360  *
2361  * @ingroup Store
2362  */
2363 EAPI void
2364 elm_store_item_update(Elm_Store_Item *sti)
2365 {
2366    EINA_SAFETY_ON_NULL_RETURN(sti);
2367    if (!EINA_MAGIC_CHECK(sti, ELM_STORE_ITEM_MAGIC)) return;
2368    Elm_Store *st = sti->store;
2369
2370    int index = elm_store_item_index_get(sti);
2371    if (index != -1)
2372      {
2373         if ((st->start_fetch_index <= index) && (index <= (st->start_fetch_index + st->cache_max)))
2374           {
2375              if (sti->fetched)
2376                {
2377                   _item_unfetch(st, index);
2378                }
2379              _item_fetch(st, index);
2380
2381              if(st->end_fetch_index < (st->total_item_count-1))
2382                {
2383                   if( (st->end_fetch_index - st->cache_max) == st->start_fetch_index)
2384                     {
2385                        _item_unfetch(st, (st->total_item_count-1));
2386                     }
2387                   else
2388                     {
2389                        st->end_fetch_index = (st->total_item_count-1);
2390                     }
2391                }
2392              if(sti->data) elm_genlist_item_update(sti->item);
2393           }
2394      }
2395    else
2396      {
2397         return;
2398      }
2399 }
2400
2401 /**
2402  * Delete the item of genlist
2403  *
2404  * @param sti The store item object
2405  *
2406  * @ingroup Store
2407  */
2408 EAPI void
2409 elm_store_item_del(Elm_Store_Item *sti)
2410 {
2411    EINA_SAFETY_ON_NULL_RETURN(sti);
2412    if (!EINA_MAGIC_CHECK(sti, ELM_STORE_ITEM_MAGIC)) return;
2413    Elm_Store *st = sti->store;
2414
2415    Eina_List *l;
2416    Eina_List*l_next;
2417    Eina_List *header_list;
2418
2419    if (st->live)
2420      {
2421         EINA_LIST_FOREACH_SAFE(st->header_items, l, l_next, header_list)
2422           {
2423              if (header_list)
2424                {
2425                   Elm_Store_Item *header_item = eina_list_nth(header_list, 0);
2426                   if(header_item && header_item->item_info && sti->item_info)
2427                     {
2428
2429                        if (header_item->item_info->group_index == sti->item_info->group_index)
2430                          {
2431                             Eina_Bool removed = EINA_FALSE;
2432                             Eina_List *in_l;
2433                             Eina_List *in_l_next;
2434                             Elm_Store_Item *remove_sti;
2435                             EINA_LIST_FOREACH_SAFE(header_list, in_l, in_l_next, remove_sti)
2436                               {
2437                                  if(remove_sti)
2438                                    {
2439                                       if (removed == EINA_TRUE)
2440                                         {
2441                                            remove_sti->item_info->index--;
2442                                         }
2443                                       else
2444                                         {
2445                                            if (remove_sti->item_info->index == sti->item_info->index)
2446                                              {
2447                                                 if (remove_sti->fetched)
2448                                                   {
2449                                                      int index = elm_store_item_index_get(remove_sti);
2450                                                      if (index != -1)
2451                                                        {
2452                                                           _item_unfetch(st, index);
2453                                                        }
2454                                                      else
2455                                                        {
2456                                                           return;
2457                                                        }
2458                                                   }
2459                                                 if (st->cb.item_free.func)
2460                                                   {
2461                                                      st->cb.item_free.func(st->cb.item_free.data, remove_sti->item_info);
2462                                                      remove_sti->item_info = NULL;
2463                                                   }
2464
2465                                                 Eina_List *temp_header_list = header_list;
2466                                                 header_list = eina_list_remove(header_list, remove_sti);
2467                                                 st->total_item_count--;
2468                                                 LKD(remove_sti->lock);
2469                                                 elm_genlist_item_del(remove_sti->item);
2470                                                 free(remove_sti);
2471
2472                                                 if (eina_list_count(header_list) == 0)
2473                                                   {
2474                                                      st->header_items = eina_list_remove(st->header_items, temp_header_list);
2475                                                      header_list = eina_list_free(header_list);
2476                                                   }
2477                                                 else if (eina_list_count(header_list) == 1)
2478                                                   {
2479                                                      Elm_Store_Item *temp_sti = eina_list_nth(header_list, 0);
2480                                                      if(temp_sti && temp_sti->item_info)
2481                                                        {
2482                                                           if (temp_sti->item_info->item_type == ELM_GENLIST_ITEM_GROUP)
2483                                                             {
2484                                                                if (temp_sti->fetched)
2485                                                                  {
2486                                                                     int index = elm_store_item_index_get(temp_sti);
2487                                                                     if (index != -1)
2488                                                                       {
2489                                                                          _item_unfetch(st, index);
2490                                                                       }
2491                                                                     else
2492                                                                       {
2493                                                                          return;
2494                                                                       }
2495                                                                  }
2496                                                                if (st->cb.item_free.func)
2497                                                                  {
2498                                                                     st->cb.item_free.func(st->cb.item_free.data, temp_sti->item_info);
2499                                                                     temp_sti->item_info = NULL;
2500                                                                  }
2501
2502                                                                header_list = eina_list_remove(header_list, temp_sti);
2503                                                                st->total_item_count--;
2504                                                                LKD(temp_sti->lock);
2505                                                                elm_genlist_item_del(temp_sti->item);
2506                                                                free(temp_sti);
2507                                                                st->header_items = eina_list_remove(st->header_items, temp_header_list);
2508                                                                header_list = eina_list_free(header_list);
2509                                                             }
2510                                                        }
2511                                                   }
2512                                                 temp_header_list = eina_list_free(temp_header_list);
2513                                                 removed = EINA_TRUE;
2514                                              }
2515                                         }
2516                                    }
2517                               }
2518                          }
2519                     }
2520                }
2521           }
2522      }
2523 }
2524
2525 // TODO: END -DBsystem store
2526