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