From 6f53582d9765ef59b267aa25dd37efb3bd838ed7 Mon Sep 17 00:00:00 2001 From: Yun ilkook Date: Fri, 8 Apr 2011 21:29:08 +0900 Subject: [PATCH] [store] add the genlist backing store for the dbsystem Change-Id: I58d20597eabbfdaab9f491396a1ab52c34675a03 --- configure.ac | 27 + debian/control | 2 +- src/bin/Makefile.am | 9 +- src/bin/test.c | 2 + src/bin/test_db_store.c | 305 +++++++ src/lib/Elementary.h.in | 224 ++--- src/lib/elm_store.c | 2225 ++++++++++++++++++++++++++++++++++++----------- 7 files changed, 2195 insertions(+), 599 deletions(-) create mode 100644 src/bin/test_db_store.c diff --git a/configure.ac b/configure.ac index f8acb1b..77b9b87 100755 --- a/configure.ac +++ b/configure.ac @@ -439,6 +439,33 @@ if test "x$want_elementary_ethumb" = "xyes" -a "x$have_elementary_ethumb" = "xno fi AC_SUBST(ELM_ETHUMB_DEF) +ELM_SQLITE3_DEF="#undef" +have_elementary_sqlite3="no" +want_elementary_sqlite3="auto" +AC_ARG_ENABLE([sqlite3], + [AC_HELP_STRING([--disable-sqlite3], [disable sqlite3 support. @<:@default=detect@:>@])], + [want_elementary_sqlite3=$enableval], []) + +if test "x$want_elementary_sqlite3" != "xno"; then + PKG_CHECK_MODULES([ELEMENTARY_SQLITE3], + [ + sqlite3 + ], + [ + AC_DEFINE(HAVE_ELEMENTARY_SQLITE3, 1, [sqlite3 support for Elementary]) + have_elementary_sqlite3="yes" + ELM_SQLITE3_DEF="#define" + requirement_elm="sqlite3 ${requirement_elm}" + ], + [have_elementary_sqlite3="no"] + ) +else + have_elementary_sqlite3="no" +fi +if test "x$want_elementary_sqlite3" = "xyes" -a "x$have_elementary_sqlite3" = "xno"; then + AC_MSG_ERROR(sqlite3 support requested, but no sqlite3 found by pkg-config.]) +fi + ELM_DEBUG_DEF="#undef" want_elementary_debug="no" AC_ARG_ENABLE([debug], diff --git a/debian/control b/debian/control index 0eebee9..27cdedc 100644 --- a/debian/control +++ b/debian/control @@ -3,7 +3,7 @@ Section: x11 Priority: optional Maintainer: Jaehwan Kim , Chuneon Park , Juyung Seo , Myungjae Lee , Woohyun Jung , Jihoon Kim , Jeonghyun Yun , Seunggyun Kim , Shinwoo Kim Uploaders: Doyoun Kang , Hyoyoung Chang , Myoungwoon Kim , Shinwoo Kim -Build-Depends: debhelper (>= 6), cdbs, libecore-dev, libevas-dev, libeet-dev, libeet-bin, libedje-dev, pkg-config, libtool, libeina-dev, libefreet-dev, libethumb-dev +Build-Depends: debhelper (>= 6), cdbs, libecore-dev, libevas-dev, libeet-dev, libeet-bin, libedje-dev, pkg-config, libtool, libeina-dev, libefreet-dev, libethumb-dev, libsqlite3-dev Standards-Version: 3.8.1 Homepage: http://www.enlightenment.org diff --git a/src/bin/Makefile.am b/src/bin/Makefile.am index 6e0c740..c66e6fc 100644 --- a/src/bin/Makefile.am +++ b/src/bin/Makefile.am @@ -16,7 +16,8 @@ AM_CPPFLAGS = \ @ELEMENTARY_EDBUS_CFLAGS@ \ @ELEMENTARY_EFREET_CFLAGS@ \ @ELEMENTARY_EWEATHER_CFLAGS@ \ -@ELEMENTARY_ETHUMB_CFLAGS@ +@ELEMENTARY_ETHUMB_CFLAGS@ \ +@ELEMENTARY_SQLITE3_CFLAGS@ if ELEMENTARY_WINDOWS_BUILD AM_CPPFLAGS += -DELEMENTARY_BUILD @@ -81,14 +82,16 @@ test_anim.c \ test_segment_control.c \ test_calendar.c \ test_diskselector.c \ -test_ctxpopup.c +test_ctxpopup.c \ +test_db_store.c elementary_test_LDADD = $(top_builddir)/src/lib/libelementary.la \ @ELEMENTARY_EWEATHER_LIBS@ \ @ELEMENTARY_EDBUS_LIBS@ \ @ELEMENTARY_EFREET_LIBS@ \ @ELEMENTARY_LIBS@ \ - @my_libs@ + @my_libs@ \ + @ELEMENTARY_SQLITE3_LIBS@ elementary_test_LDFLAGS = elementary_config_SOURCES = \ diff --git a/src/bin/test.c b/src/bin/test.c index af8fc60..0b78c4e 100644 --- a/src/bin/test.c +++ b/src/bin/test.c @@ -84,6 +84,7 @@ void test_anim(void *data, Evas_Object *obj, void *event_info); void test_segment_control(void *data, Evas_Object *obj, void *event_info); void test_diskselector(void *data, Evas_Object *obj, void *event_info); void test_ctxpopup(void *data, Evas_Object *obj, void *event_info); +void test_db_store(void *data, Evas_Object * obj, void *event_info); struct elm_test { @@ -287,6 +288,7 @@ my_win_main(void) ADD_TEST("Calendar 2", test_calendar2); ADD_TEST("Disk Selector", test_diskselector); ADD_TEST("Ctxpopup", test_ctxpopup); + ADD_TEST("Db Store", test_db_store); #undef ADD_TEST if (tests) diff --git a/src/bin/test_db_store.c b/src/bin/test_db_store.c new file mode 100644 index 0000000..028c8ce --- /dev/null +++ b/src/bin/test_db_store.c @@ -0,0 +1,305 @@ +#include + +#ifdef HAVE_CONFIG_H +# include "elementary_config.h" +#endif +#ifndef ELM_LIB_QUICKLAUNCH +#ifdef HAVE_ELEMENTARY_SQLITE3 +#include "sqlite3.h" +#endif + +#define BUF_SIZE 1024 +#define ITEM_COUNT 1000 +#define BLOCK_COUNT 10 +#define GROUP_MAX (ITEM_COUNT/5) + +typedef struct _My_Contact My_Contact; +typedef struct _Group_Title Group_Title; + +struct _My_Contact +{ + int n_id; + char *psz_name; + char *psz_jobtitle; + char *psz_mobile; +}; + +struct _Group_Title +{ + char *group_title; +}; + +static int group_index = -1; +static sqlite3 *p_db = NULL; +static char *_st_store_group_custom_label_get(void *data, Elm_Store_Item * sti, const char *part); + +// callbacks just to see user interacting with genlist +static void +_st_selected(void *data __UNUSED__, Evas_Object * obj __UNUSED__, void *event_info) +{ + printf("selected: %p\n", event_info); +} + +static void +_st_clicked(void *data __UNUSED__, Evas_Object * obj __UNUSED__, void *event_info) +{ + printf("clicked: %p\n", event_info); +} + +static void +_st_longpress(void *data __UNUSED__, Evas_Object * obj __UNUSED__, void *event_info) +{ + printf("longpress %p\n", event_info); +} + +// store callbacks to handle loading/parsing/freeing of store items from src +static char *group_title[GROUP_MAX]; + +static Elm_Genlist_Item_Class itc1 = { + "message_db", {NULL, NULL, NULL, NULL} +}; + +static Elm_Genlist_Item_Class itc2 = { + "group_title", {NULL, NULL, NULL, NULL} +}; + +static const Elm_Store_Item_Mapping it1_mapping[] = { + { + ELM_STORE_ITEM_MAPPING_LABEL, + "elm.title.1", ELM_STORE_ITEM_MAPPING_OFFSET (My_Contact, psz_name), + {.empty = { + EINA_TRUE}}}, + { + ELM_STORE_ITEM_MAPPING_LABEL, + "elm.title.2", ELM_STORE_ITEM_MAPPING_OFFSET (My_Contact, psz_jobtitle), + {.empty = { + EINA_TRUE}}}, + { + ELM_STORE_ITEM_MAPPING_LABEL, + "elm.text", ELM_STORE_ITEM_MAPPING_OFFSET (My_Contact, psz_mobile), + {.empty = { + EINA_TRUE}}}, + ELM_STORE_ITEM_MAPPING_END +}; + +static const Elm_Store_Item_Mapping it2_mapping[] = { + { + ELM_STORE_ITEM_MAPPING_CUSTOM, + "elm.text", 0, + {.custom = { + (Elm_Store_Item_Mapping_Cb)_st_store_group_custom_label_get}}}, + ELM_STORE_ITEM_MAPPING_END +}; + +static char * +_st_store_group_custom_label_get(void *data, Elm_Store_Item * sti, const char *part) +{ + if (!strcmp(part, "elm.text")) + return strdup("group title"); + + return strdup(""); +} + +////// **** WARNING *********************************************************** +//// * This function runs inside a thread outside efl mainloop. Be careful! * +// ************************************************************************ +static Eina_Bool +_st_store_list(void *data __UNUSED__, Elm_Store_Item_Info * item_info) +{ + if ((item_info->index % 5) == 0) + { + char gtext[128]; + int index_label = item_info->index / 5; + sprintf(gtext, "group title (%d)", index_label); + group_title[index_label] = strdup(gtext); + group_index = index_label; + + item_info->item_type = ELM_GENLIST_ITEM_GROUP; + item_info->group_index = group_index; + item_info->rec_item = EINA_FALSE; + item_info->pre_group_index = -1; + item_info->item_class = &itc2; + item_info->mapping = it2_mapping; + } + else + { + item_info->item_type = ELM_GENLIST_ITEM_NONE; + item_info->group_index = group_index; + item_info->rec_item = EINA_FALSE; + item_info->pre_group_index = -1; + item_info->item_class = &itc1; + item_info->mapping = it1_mapping; + } + + item_info->data = NULL; + return EINA_TRUE; +} + +// ************************************************************************ +//// * End of separate thread function. * +////// ************************************************************************ + +////// **** WARNING *********************************************************** +//// * This function runs inside a thread outside efl mainloop. Be careful! * +// ************************************************************************ + +static void +_st_store_fetch(void *data __UNUSED__, Elm_Store_Item * sti, Elm_Store_Item_Info * item_info) +{ + if (item_info->item_type == ELM_GENLIST_ITEM_GROUP) + { + Group_Title *pGpTitle; + pGpTitle = calloc(1, sizeof(Group_Title)); + pGpTitle->group_title = strdup(group_title[item_info->group_index]); + elm_store_item_data_set(sti, pGpTitle); + } + else + { + + My_Contact *pmyct; + + // alloc my item in memory that holds data to show in the list +#ifdef HAVE_ELEMENTARY_SQLITE3 + sqlite3_stmt* stmt = NULL; + char szbuf[BUF_SIZE] = {0, }; + int rc = 0; + + int start_idx = elm_store_item_data_index_get(sti); + int fetch_count = 1; + sqlite3 *pdb = elm_store_dbsystem_db_get(sti); + + snprintf(szbuf, BUF_SIZE, "SELECT * FROM tblEmpList ORDER BY id ASC LIMIT ?,?;"); + + rc = sqlite3_prepare(pdb, szbuf, strlen(szbuf), &stmt, NULL); + rc = sqlite3_bind_int(stmt, 1, start_idx); + rc = sqlite3_bind_int(stmt, 2, fetch_count); + rc = sqlite3_step(stmt); + + pmyct = calloc(1, sizeof(My_Contact)); + pmyct->n_id = sqlite3_column_int(stmt, 0); + pmyct->psz_name = strdup((const char *)sqlite3_column_text(stmt, 1)); + pmyct->psz_jobtitle= strdup((const char *)sqlite3_column_text(stmt, 2)); + pmyct->psz_mobile = strdup((const char *)sqlite3_column_text(stmt, 3)); + + rc = sqlite3_finalize(stmt); +#else + int start_idx = elm_store_item_data_index_get(sti); + pmyct = calloc(1, sizeof(My_Contact)); + pmyct->n_id = start_idx; + pmyct->psz_name = strdup("Name"); + pmyct->psz_jobtitle = strdup("Title"); + pmyct->psz_mobile = strdup("Mobile"); +#endif + elm_store_item_data_set(sti, pmyct); + } + return; +} + +// ************************************************************************ +//// * End of separate thread function. * +////// ************************************************************************ +static void +_st_store_unfetch(void *data __UNUSED__, Elm_Store_Item * sti, Elm_Store_Item_Info * item_info) +{ + if (item_info->item_type == ELM_GENLIST_ITEM_GROUP) + { + Group_Title *myit = elm_store_item_data_get(sti); + + if (!myit) + return; + if (myit->group_title) + free(myit->group_title); + free(myit); + + } + else + { + My_Contact *myit = elm_store_item_data_get(sti); + + if (!myit) + return; + if (myit->psz_name) + free(myit->psz_name); + if (myit->psz_jobtitle) + free(myit->psz_jobtitle); + if (myit->psz_mobile) + free(myit->psz_mobile); + free(myit); + } + elm_store_item_data_set(sti, NULL); +} + +static void +_st_store_item_select(void *data, Evas_Object * obj, void *event_info) +{ + Elm_Genlist_Item *gli = event_info; + Elm_Store_Item *sti = elm_genlist_item_data_get(gli); + + if (sti) + { + int index = elm_store_item_data_index_get(sti); + printf("item %d is selected\n", index); + elm_genlist_item_selected_set(gli, EINA_FALSE); + } +} + +void +test_db_store(void *data __UNUSED__, Evas_Object * obj __UNUSED__, void *event_info __UNUSED__) +{ + Evas_Object *win, *bg, *gl, *bx; + Elm_Store *st; + + win = elm_win_add(NULL, "db-store", ELM_WIN_BASIC); + elm_win_title_set(win, "Store"); + elm_win_autodel_set(win, 1); + + bg = elm_bg_add(win); + elm_win_resize_object_add(win, bg); + evas_object_size_hint_weight_set(bg, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_show(bg); + + bx = elm_box_add(win); + evas_object_size_hint_weight_set(bx, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + elm_win_resize_object_add(win, bx); + evas_object_show(bx); + + gl = elm_genlist_add(win); + elm_genlist_homogeneous_set(gl, EINA_TRUE); + elm_genlist_compress_mode_set(gl, EINA_TRUE); + elm_genlist_block_count_set(gl, BLOCK_COUNT); + elm_genlist_height_for_width_mode_set(gl, EINA_TRUE); + evas_object_smart_callback_add(gl, "selected", _st_selected, NULL); + evas_object_smart_callback_add(gl, "clicked", _st_clicked, NULL); + evas_object_smart_callback_add(gl, "longpressed", _st_longpress, NULL); + evas_object_size_hint_weight_set(gl, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_size_hint_align_set(gl, EVAS_HINT_FILL, EVAS_HINT_FILL); + elm_box_pack_end(bx, gl); + evas_object_show(gl); + + // Set the db handler to store. after open it + // Then store will add items as you set the item count number +#ifdef HAVE_ELEMENTARY_SQLITE3 + if (!p_db) + { + int rc = sqlite3_open("./genlist.db", &p_db); + if(SQLITE_OK != rc) + { + printf("Fail to open DB ./genlist.db\n"); + } + } +#endif + + st = elm_store_dbsystem_new(); + elm_store_fetch_thread_set(st, EINA_TRUE); + elm_store_item_count_set(st, ITEM_COUNT); + elm_store_list_func_set(st, _st_store_list, NULL); + elm_store_fetch_func_set(st, _st_store_fetch, NULL); + elm_store_unfetch_func_set(st, _st_store_unfetch, NULL); + elm_store_item_select_func_set(st, (Elm_Store_Item_Select_Cb)_st_store_item_select, NULL); + elm_store_target_genlist_set(st, gl); + elm_store_dbsystem_db_set(st, p_db); + + evas_object_resize(win, 480, 800); + evas_object_show(win); +} +#endif diff --git a/src/lib/Elementary.h.in b/src/lib/Elementary.h.in index 45b1741..8114cfa 100644 --- a/src/lib/Elementary.h.in +++ b/src/lib/Elementary.h.in @@ -3203,116 +3203,136 @@ extern "C" { EAPI void elm_imageslider_prev(Evas_Object *obj) EINA_ARG_NONNULL(1); EAPI void elm_imageslider_next(Evas_Object *obj) EINA_ARG_NONNULL(1); - typedef struct _Elm_Store Elm_Store; - typedef struct _Elm_Store_Filesystem Elm_Store_Filesystem; - typedef struct _Elm_Store_Item Elm_Store_Item; - typedef struct _Elm_Store_Item_Filesystem Elm_Store_Item_Filesystem; - typedef struct _Elm_Store_Item_Info Elm_Store_Item_Info; - typedef struct _Elm_Store_Item_Info_Filesystem Elm_Store_Item_Info_Filesystem; - typedef struct _Elm_Store_Item_Mapping Elm_Store_Item_Mapping; - typedef struct _Elm_Store_Item_Mapping_Empty Elm_Store_Item_Mapping_Empty; - typedef struct _Elm_Store_Item_Mapping_Icon Elm_Store_Item_Mapping_Icon; - typedef struct _Elm_Store_Item_Mapping_Photo Elm_Store_Item_Mapping_Photo; - typedef struct _Elm_Store_Item_Mapping_Custom Elm_Store_Item_Mapping_Custom; - - typedef Eina_Bool (*Elm_Store_Item_List_Cb) (void *data, Elm_Store_Item_Info *info); - typedef void (*Elm_Store_Item_Fetch_Cb) (void *data, Elm_Store_Item *sti); - typedef void (*Elm_Store_Item_Unfetch_Cb) (void *data, Elm_Store_Item *sti); - typedef void *(*Elm_Store_Item_Mapping_Cb) (void *data, Elm_Store_Item *sti, const char *part); - - typedef enum - { - ELM_STORE_ITEM_MAPPING_NONE = 0, - ELM_STORE_ITEM_MAPPING_LABEL, // const char * -> label - ELM_STORE_ITEM_MAPPING_STATE, // Eina_Bool -> state - ELM_STORE_ITEM_MAPPING_ICON, // char * -> icon path - ELM_STORE_ITEM_MAPPING_PHOTO, // char * -> photo path - ELM_STORE_ITEM_MAPPING_CUSTOM, // item->custom(it->data, it, part) -> void * (-> any) - // can add more here as needed by common apps - ELM_STORE_ITEM_MAPPING_LAST - } Elm_Store_Item_Mapping_Type; - - struct _Elm_Store_Item_Mapping_Icon - { - // FIXME: allow edje file icons - int w, h; - Elm_Icon_Lookup_Order lookup_order; - Eina_Bool standard_name : 1; - Eina_Bool no_scale : 1; - Eina_Bool smooth : 1; - Eina_Bool scale_up : 1; - Eina_Bool scale_down : 1; - }; - - struct _Elm_Store_Item_Mapping_Empty - { - Eina_Bool dummy; - }; + /* Store */ + typedef struct _Elm_Store Elm_Store; + typedef struct _Elm_Store_DBsystem Elm_Store_DBsystem; + typedef struct _Elm_Store_Filesystem Elm_Store_Filesystem; + typedef struct _Elm_Store_Item Elm_Store_Item; + typedef struct _Elm_Store_Item_DBsystem Elm_Store_Item_DBsystem; + typedef struct _Elm_Store_Item_Filesystem Elm_Store_Item_Filesystem; + typedef struct _Elm_Store_Item_Info Elm_Store_Item_Info; + typedef struct _Elm_Store_Item_Info_Filesystem Elm_Store_Item_Info_Filesystem; + typedef struct _Elm_Store_Item_Mapping Elm_Store_Item_Mapping; + typedef struct _Elm_Store_Item_Mapping_Empty Elm_Store_Item_Mapping_Empty; + typedef struct _Elm_Store_Item_Mapping_Icon Elm_Store_Item_Mapping_Icon; + typedef struct _Elm_Store_Item_Mapping_Photo Elm_Store_Item_Mapping_Photo; + typedef struct _Elm_Store_Item_Mapping_Custom Elm_Store_Item_Mapping_Custom; + + typedef Eina_Bool (*Elm_Store_Item_List_Cb) (void *data, Elm_Store_Item_Info *info); + typedef void (*Elm_Store_Item_Fetch_Cb) (void *data, Elm_Store_Item *sti, Elm_Store_Item_Info *info); + typedef void (*Elm_Store_Item_Unfetch_Cb) (void *data, Elm_Store_Item *sti, Elm_Store_Item_Info *info); + typedef void (*Elm_Store_Item_Select_Cb) (void *data, Elm_Store_Item *sti); + typedef void (*Elm_Store_Item_Sort_Cb) (void *data, Elm_Store_Item *sti, Elm_Store_Item *next); + typedef void *(*Elm_Store_Item_Mapping_Cb) (void *data, Elm_Store_Item *sti, const char *part); - struct _Elm_Store_Item_Mapping_Photo - { - int size; - }; + typedef enum + { + ELM_STORE_ITEM_MAPPING_NONE = 0, + ELM_STORE_ITEM_MAPPING_LABEL, // const char * -> label + ELM_STORE_ITEM_MAPPING_STATE, // Eina_Bool -> state + ELM_STORE_ITEM_MAPPING_ICON, // char * -> icon path + ELM_STORE_ITEM_MAPPING_PHOTO, // char * -> photo path + ELM_STORE_ITEM_MAPPING_CUSTOM, // item->custom(it->data, it, part) -> void * (-> any) + // can add more here as needed by common apps + ELM_STORE_ITEM_MAPPING_LAST + } Elm_Store_Item_Mapping_Type; + + struct _Elm_Store_Item_Mapping_Icon + { + // FIXME: allow edje file icons + int w, h; + Elm_Icon_Lookup_Order lookup_order; + Eina_Bool standard_name : 1; + Eina_Bool no_scale : 1; + Eina_Bool smooth : 1; + Eina_Bool scale_up : 1; + Eina_Bool scale_down : 1; + }; - struct _Elm_Store_Item_Mapping_Custom - { - Elm_Store_Item_Mapping_Cb func; - }; + struct _Elm_Store_Item_Mapping_Empty + { + Eina_Bool dummy; + }; - struct _Elm_Store_Item_Mapping - { - Elm_Store_Item_Mapping_Type type; - const char *part; - int offset; - union { - Elm_Store_Item_Mapping_Empty empty; - Elm_Store_Item_Mapping_Icon icon; - Elm_Store_Item_Mapping_Photo photo; - Elm_Store_Item_Mapping_Custom custom; - // add more types here - } details; - }; - - struct _Elm_Store_Item_Info - { - Elm_Genlist_Item_Class *item_class; - const Elm_Store_Item_Mapping *mapping; - void *data; - char *sort_id; - }; + struct _Elm_Store_Item_Mapping_Photo + { + int size; + }; - struct _Elm_Store_Item_Info_Filesystem - { - Elm_Store_Item_Info base; - char *path; - }; + struct _Elm_Store_Item_Mapping_Custom + { + Elm_Store_Item_Mapping_Cb func; + }; + + struct _Elm_Store_Item_Mapping + { + Elm_Store_Item_Mapping_Type type; + const char *part; + int offset; + union { + Elm_Store_Item_Mapping_Empty empty; + Elm_Store_Item_Mapping_Icon icon; + Elm_Store_Item_Mapping_Photo photo; + Elm_Store_Item_Mapping_Custom custom; + // add more types here + } details; + }; + + struct _Elm_Store_Item_Info + { + int index; + int item_type; + int group_index; + Eina_Bool rec_item; + int pre_group_index; + + Elm_Genlist_Item_Class *item_class; + const Elm_Store_Item_Mapping *mapping; + void *data; + char *sort_id; + }; + + struct _Elm_Store_Item_Info_Filesystem + { + Elm_Store_Item_Info base; + char *path; + }; #define ELM_STORE_ITEM_MAPPING_END { ELM_STORE_ITEM_MAPPING_NONE, NULL, 0, { .empty = { EINA_TRUE } } } #define ELM_STORE_ITEM_MAPPING_OFFSET(st, it) offsetof(st, it) - EAPI void elm_store_free(Elm_Store *st); - - EAPI Elm_Store *elm_store_filesystem_new(void); - EAPI void elm_store_filesystem_directory_set(Elm_Store *st, const char *dir) EINA_ARG_NONNULL(1); - EAPI const char *elm_store_filesystem_directory_get(const Elm_Store *st) EINA_ARG_NONNULL(1); - EAPI const char *elm_store_item_filesystem_path_get(const Elm_Store_Item *sti) EINA_ARG_NONNULL(1); - - EAPI void elm_store_target_genlist_set(Elm_Store *st, Evas_Object *obj) EINA_ARG_NONNULL(1); - - EAPI void elm_store_cache_set(Elm_Store *st, int max) EINA_ARG_NONNULL(1); - EAPI int elm_store_cache_get(const Elm_Store *st) EINA_ARG_NONNULL(1); - EAPI void elm_store_list_func_set(Elm_Store *st, Elm_Store_Item_List_Cb func, const void *data) EINA_ARG_NONNULL(1, 2); - EAPI void elm_store_fetch_func_set(Elm_Store *st, Elm_Store_Item_Fetch_Cb func, const void *data) EINA_ARG_NONNULL(1, 2); - EAPI void elm_store_fetch_thread_set(Elm_Store *st, Eina_Bool use_thread) EINA_ARG_NONNULL(1); - EAPI Eina_Bool elm_store_fetch_thread_get(const Elm_Store *st) EINA_ARG_NONNULL(1); - - EAPI void elm_store_unfetch_func_set(Elm_Store *st, Elm_Store_Item_Unfetch_Cb func, const void *data) EINA_ARG_NONNULL(1, 2); - EAPI void elm_store_sorted_set(Elm_Store *st, Eina_Bool sorted) EINA_ARG_NONNULL(1); - EAPI Eina_Bool elm_store_sorted_get(const Elm_Store *st) EINA_ARG_NONNULL(1); - EAPI void elm_store_item_data_set(Elm_Store_Item *sti, void *data) EINA_ARG_NONNULL(1); - EAPI void *elm_store_item_data_get(Elm_Store_Item *sti) EINA_ARG_NONNULL(1); - EAPI const Elm_Store *elm_store_item_store_get(const Elm_Store_Item *sti) EINA_ARG_NONNULL(1); - EAPI const Elm_Genlist_Item *elm_store_item_genlist_item_get(const Elm_Store_Item *sti) EINA_ARG_NONNULL(1); + EAPI Elm_Store *elm_store_dbsystem_new(void); + EAPI void elm_store_item_count_set(Elm_Store *st, int count) EINA_ARG_NONNULL(1); + EAPI void elm_store_item_select_func_set(Elm_Store *st, Elm_Store_Item_Select_Cb func, const void *data) EINA_ARG_NONNULL(1); + EAPI void elm_store_item_sort_func_set(Elm_Store *st, Elm_Store_Item_Sort_Cb func, const void *data) EINA_ARG_NONNULL(1); + EAPI int elm_store_item_data_index_get(const Elm_Store_Item *sti) EINA_ARG_NONNULL(1); + EAPI void *elm_store_dbsystem_db_get(const Elm_Store_Item *sti) EINA_ARG_NONNULL(1); + EAPI void elm_store_dbsystem_db_set(Elm_Store *store, void *pDB) EINA_ARG_NONNULL(1); + EAPI int elm_store_item_index_get(const Elm_Store_Item *sti) EINA_ARG_NONNULL(1); + EAPI Elm_Store_Item *elm_store_item_add(Elm_Store *st, Elm_Store_Item_Info *info) EINA_ARG_NONNULL(1); + EAPI void elm_store_item_update(Elm_Store *st, Elm_Store_Item *sti) EINA_ARG_NONNULL(1); + EAPI void elm_store_visible_items_update(Elm_Store *st) EINA_ARG_NONNULL(1); + EAPI void elm_store_item_del(Elm_Store_Item *sti) EINA_ARG_NONNULL(1); + EAPI void elm_store_free(Elm_Store *st); + EAPI Elm_Store *elm_store_filesystem_new(void); + EAPI void elm_store_filesystem_directory_set(Elm_Store *st, const char *dir) EINA_ARG_NONNULL(1); + EAPI const char *elm_store_filesystem_directory_get(const Elm_Store *st) EINA_ARG_NONNULL(1); + EAPI const char *elm_store_item_filesystem_path_get(const Elm_Store_Item *sti) EINA_ARG_NONNULL(1); + EAPI void elm_store_target_genlist_set(Elm_Store *st, Evas_Object *obj) EINA_ARG_NONNULL(1); + EAPI void elm_store_cache_set(Elm_Store *st, int max) EINA_ARG_NONNULL(1); + EAPI int elm_store_cache_get(const Elm_Store *st) EINA_ARG_NONNULL(1); + EAPI void elm_store_list_func_set(Elm_Store *st, Elm_Store_Item_List_Cb func, const void *data) EINA_ARG_NONNULL(1, 2); + EAPI void elm_store_fetch_func_set(Elm_Store *st, Elm_Store_Item_Fetch_Cb func, const void *data) EINA_ARG_NONNULL(1, 2); + EAPI void elm_store_fetch_thread_set(Elm_Store *st, Eina_Bool use_thread) EINA_ARG_NONNULL(1); + EAPI Eina_Bool elm_store_fetch_thread_get(const Elm_Store *st) EINA_ARG_NONNULL(1); + EAPI void elm_store_unfetch_func_set(Elm_Store *st, Elm_Store_Item_Unfetch_Cb func, const void *data) EINA_ARG_NONNULL(1, 2); + EAPI void elm_store_sorted_set(Elm_Store *st, Eina_Bool sorted) EINA_ARG_NONNULL(1); + EAPI Eina_Bool elm_store_sorted_get(const Elm_Store *st) EINA_ARG_NONNULL(1); + EAPI void elm_store_item_data_set(Elm_Store_Item *sti, void *data) EINA_ARG_NONNULL(1); + EAPI void *elm_store_item_data_get(Elm_Store_Item *sti) EINA_ARG_NONNULL(1); + EAPI const Elm_Store *elm_store_item_store_get(const Elm_Store_Item *sti) EINA_ARG_NONNULL(1); + EAPI const Elm_Genlist_Item *elm_store_item_genlist_item_get(const Elm_Store_Item *sti) EINA_ARG_NONNULL(1); + #ifdef __cplusplus } diff --git a/src/lib/elm_store.c b/src/lib/elm_store.c index dba552b..cf2d601 100644 --- a/src/lib/elm_store.c +++ b/src/lib/elm_store.c @@ -3,7 +3,7 @@ #include "elm_priv.h" #ifndef EFL_HAVE_THREADS -# error "No thread support. Required." +# error "No thread support. Required." #endif #ifdef EFL_HAVE_POSIX_THREADS @@ -26,136 +26,175 @@ #define ELM_STORE_MAGIC 0x3f89ea56 #define ELM_STORE_FILESYSTEM_MAGIC 0x3f89ea57 +#define ELM_STORE_DBSYSTEM_MAGIC 0x3f89ea58 #define ELM_STORE_ITEM_MAGIC 0x5afe8c1d +#define CACHE_COUNT 128 +#define SCREEN_ITEM_COUNT 10 struct _Elm_Store { - EINA_MAGIC; - void (*free)(Elm_Store *store); - struct { - void (*free)(Elm_Store_Item *item); - } item; - Evas_Object *genlist; - Ecore_Thread *list_th; - Eina_Inlist *items; - Eina_List *realized; - int realized_count; - int cache_max; - struct { - struct { - Elm_Store_Item_List_Cb func; - void *data; - } list; - struct { - Elm_Store_Item_Fetch_Cb func; - void *data; - } fetch; - struct { - Elm_Store_Item_Unfetch_Cb func; - void *data; - } unfetch; - } cb; - Eina_Bool sorted : 1; - Eina_Bool fetch_thread : 1; + EINA_MAGIC; + void (*free)(Elm_Store *store); + struct { + void (*free)(Elm_Store_Item *item); + } item; + Evas_Object *genlist; + Ecore_Thread *list_th; + Eina_Inlist *items; + Eina_List *realized; + int realized_count; + int cache_max; + int current_top_index; + int start_fetch_index; + int end_fetch_index; + int item_count; + int total_count; + int block_count; + int type; + Eina_List *header_items; + struct { + struct { + Elm_Store_Item_List_Cb func; + void *data; + } list; + struct { + Elm_Store_Item_Fetch_Cb func; + void *data; + } fetch; + struct { + Elm_Store_Item_Unfetch_Cb func; + void *data; + } unfetch; + struct { + Elm_Store_Item_Select_Cb func; + void *data; + } item_select; + struct { + Elm_Store_Item_Sort_Cb func; + void *data; + } item_sort; + } cb; + Eina_Bool sorted : 1; + Eina_Bool fetch_thread : 1; + Eina_Bool multi_load : 1; + Eina_Bool live : 1; }; struct _Elm_Store_Item { - EINA_INLIST; - EINA_MAGIC; - Elm_Store *store; - Elm_Genlist_Item *item; - Ecore_Thread *fetch_th; - Ecore_Job *eval_job; - const Elm_Store_Item_Mapping *mapping; - void *data; - LK(lock); - Eina_Bool live : 1; - Eina_Bool was_live : 1; - Eina_Bool realized : 1; - Eina_Bool fetched : 1; + EINA_INLIST; + EINA_MAGIC; + Elm_Store *store; + Elm_Genlist_Item *item; + Ecore_Thread *fetch_th; + Ecore_Job *eval_job; + const Elm_Store_Item_Mapping *mapping; + void *data; + Elm_Store_Item_Info *item_info; + LK(lock); + Eina_Bool live : 1; + Eina_Bool was_live : 1; + Eina_Bool realized : 1; + Eina_Bool fetched : 1; }; struct _Elm_Store_Filesystem { - Elm_Store base; - EINA_MAGIC; - const char *dir; + Elm_Store base; + EINA_MAGIC; + const char *dir; }; struct _Elm_Store_Item_Filesystem { - Elm_Store_Item base; - const char *path; + Elm_Store_Item base; + const char *path; +}; + +struct _Elm_Store_DBsystem +{ + Elm_Store base; + EINA_MAGIC; + void *p_db; }; static Elm_Genlist_Item_Class _store_item_class; +static char *_item_label_get(void *data, Evas_Object *obj __UNUSED__, const char *part); +static Evas_Object *_item_icon_get(void *data, Evas_Object *obj, const char *part); +static void _item_del(void *data __UNUSED__, Evas_Object *obj __UNUSED__); +static void _store_free(Elm_Store *st); +static void _item_free(Elm_Store_Item *sti); +static void _item_realized(void *data, Evas_Object *obj __UNUSED__, void *event_info); +static void _item_unrealized(void *data, Evas_Object *obj __UNUSED__, void *event_info); +static void _genlist_del(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__); +static Elm_Store_Item *_item_unfetch(Elm_Store *st, int index); + static void _store_cache_trim(Elm_Store *st) { - while ((st->realized ) && - (((int)eina_list_count(st->realized) - st->realized_count) + while ((st->realized ) && + (((int)eina_list_count(st->realized) - st->realized_count) > st->cache_max)) - { - Elm_Store_Item *sti = st->realized->data; - if (sti->realized) - { - st->realized = eina_list_remove_list(st->realized, st->realized); - sti->realized = EINA_FALSE; - } - LKL(sti->lock); - if (!sti->fetched) - { - LKU(sti->lock); - if (sti->fetch_th) - { - ecore_thread_cancel(sti->fetch_th); - sti->fetch_th = NULL; - } - LKL(sti->lock); - } - sti->fetched = EINA_FALSE; - LKU(sti->lock); - if (st->cb.unfetch.func) - st->cb.unfetch.func(st->cb.unfetch.data, sti); - LKL(sti->lock); - sti->data = NULL; - LKU(sti->lock); - } -} - -static void + { + Elm_Store_Item *sti = st->realized->data; + if (sti->realized) + { + st->realized = eina_list_remove_list(st->realized, st->realized); + sti->realized = EINA_FALSE; + } + LKL(sti->lock); + if (!sti->fetched) + { + LKU(sti->lock); + if (sti->fetch_th) + { + ecore_thread_cancel(sti->fetch_th); + sti->fetch_th = NULL; + } + LKL(sti->lock); + } + sti->fetched = EINA_FALSE; + LKU(sti->lock); + if (st->cb.unfetch.func) + st->cb.unfetch.func(st->cb.unfetch.data, sti, NULL); + LKL(sti->lock); + sti->data = NULL; + LKU(sti->lock); + } +} + +static void _store_genlist_del(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__) { - Elm_Store *st = data; - st->genlist = NULL; - if (st->list_th) - { - ecore_thread_cancel(st->list_th); - st->list_th = NULL; - } - eina_list_free(st->realized); - while (st->items) - { - Elm_Store_Item *sti = (Elm_Store_Item *)st->items; - if (sti->eval_job) ecore_job_del(sti->eval_job); - if (sti->fetch_th) - { - ecore_thread_cancel(sti->fetch_th); - sti->fetch_th = NULL; - } - if (sti->store->item.free) sti->store->item.free(sti); - if (sti->data) - { - if (st->cb.unfetch.func) - st->cb.unfetch.func(st->cb.unfetch.data, sti); - sti->data = NULL; - } - LKD(sti->lock); - free(sti); - } - // FIXME: kill threads and more + Elm_Store *st = data; + st->genlist = NULL; + if (st->list_th) + { + ecore_thread_cancel(st->list_th); + st->list_th = NULL; + } + eina_list_free(st->realized); + while (st->items) + { + Elm_Store_Item *sti = (Elm_Store_Item *)st->items; + if (sti->eval_job) ecore_job_del(sti->eval_job); + if (sti->fetch_th) + { + ecore_thread_cancel(sti->fetch_th); + sti->fetch_th = NULL; + } + if (sti->store->item.free) sti->store->item.free(sti); + if (sti->data) + { + if (st->cb.unfetch.func) + st->cb.unfetch.func(st->cb.unfetch.data, sti, NULL); + sti->data = NULL; + } + LKD(sti->lock); + free(sti); + } + // FIXME: kill threads and more } ////// **** WARNING *********************************************************** @@ -165,22 +204,22 @@ _store_genlist_del(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, static void _store_filesystem_fetch_do(void *data, Ecore_Thread *th __UNUSED__) { - Elm_Store_Item *sti = data; - LKL(sti->lock); - if (sti->data) - { - LKU(sti->lock); - return; - } - if (!sti->fetched) - { - LKU(sti->lock); - if (sti->store->cb.fetch.func) - sti->store->cb.fetch.func(sti->store->cb.fetch.data, sti); - LKL(sti->lock); - sti->fetched = EINA_TRUE; - } - LKU(sti->lock); + Elm_Store_Item *sti = data; + LKL(sti->lock); + if (sti->data) + { + LKU(sti->lock); + return; + } + if (!sti->fetched) + { + LKU(sti->lock); + if (sti->store->cb.fetch.func) + sti->store->cb.fetch.func(sti->store->cb.fetch.data, sti, NULL); + LKL(sti->lock); + sti->fetched = EINA_TRUE; + } + LKU(sti->lock); } // ************************************************************************ //// * End of separate thread function. * @@ -189,184 +228,184 @@ _store_filesystem_fetch_do(void *data, Ecore_Thread *th __UNUSED__) static void _store_filesystem_fetch_end(void *data, Ecore_Thread *th) { - Elm_Store_Item *sti = data; - LKL(sti->lock); - if (sti->data) elm_genlist_item_update(sti->item); - LKU(sti->lock); - if (th == sti->fetch_th) sti->fetch_th = NULL; + Elm_Store_Item *sti = data; + LKL(sti->lock); + if (sti->data) elm_genlist_item_update(sti->item); + LKU(sti->lock); + if (th == sti->fetch_th) sti->fetch_th = NULL; } /* TODO: refactor lock part into core? this does not depend on filesystm part */ static void _store_filesystem_fetch_cancel(void *data, Ecore_Thread *th) { - Elm_Store_Item *sti = data; - LKL(sti->lock); - if (th == sti->fetch_th) sti->fetch_th = NULL; - if (sti->data) elm_genlist_item_update(sti->item); - LKU(sti->lock); + Elm_Store_Item *sti = data; + LKL(sti->lock); + if (th == sti->fetch_th) sti->fetch_th = NULL; + if (sti->data) elm_genlist_item_update(sti->item); + LKU(sti->lock); } static void _store_item_eval(void *data) { - Elm_Store_Item *sti = data; - sti->eval_job = NULL; - if (sti->live == sti->was_live) return; - sti->was_live = sti->live; - if (sti->live) - { - _store_cache_trim(sti->store); - if (sti->realized) - sti->store->realized = eina_list_remove(sti->store->realized, sti); - sti->store->realized = eina_list_append(sti->store->realized, sti); - sti->realized = EINA_TRUE; - if ((sti->store->fetch_thread) && (!sti->fetch_th)) - sti->fetch_th = ecore_thread_run(_store_filesystem_fetch_do, - _store_filesystem_fetch_end, - _store_filesystem_fetch_cancel, - sti); - else if ((!sti->store->fetch_thread)) - { - _store_filesystem_fetch_do(sti, NULL); - _store_filesystem_fetch_end(sti, NULL); - } - } - else - { - if (sti->fetch_th) - { - ecore_thread_cancel(sti->fetch_th); - sti->fetch_th = NULL; - } - _store_cache_trim(sti->store); - } + Elm_Store_Item *sti = data; + sti->eval_job = NULL; + if (sti->live == sti->was_live) return; + sti->was_live = sti->live; + if (sti->live) + { + _store_cache_trim(sti->store); + if (sti->realized) + sti->store->realized = eina_list_remove(sti->store->realized, sti); + sti->store->realized = eina_list_append(sti->store->realized, sti); + sti->realized = EINA_TRUE; + if ((sti->store->fetch_thread) && (!sti->fetch_th)) + sti->fetch_th = ecore_thread_run(_store_filesystem_fetch_do, + _store_filesystem_fetch_end, + _store_filesystem_fetch_cancel, + sti); + else if ((!sti->store->fetch_thread)) + { + _store_filesystem_fetch_do(sti, NULL); + _store_filesystem_fetch_end(sti, NULL); + } + } + else + { + if (sti->fetch_th) + { + ecore_thread_cancel(sti->fetch_th); + sti->fetch_th = NULL; + } + _store_cache_trim(sti->store); + } } static void _store_genlist_item_realized(void *data, Evas_Object *obj __UNUSED__, void *event_info) { - Elm_Store *st = data; - Elm_Genlist_Item *gli = event_info; - Elm_Store_Item *sti = elm_genlist_item_data_get(gli); - if (!sti) return; - st->realized_count++; - sti->live = EINA_TRUE; - if (sti->eval_job) ecore_job_del(sti->eval_job); - sti->eval_job = ecore_job_add(_store_item_eval, sti); + Elm_Store *st = data; + Elm_Genlist_Item *gli = event_info; + Elm_Store_Item *sti = elm_genlist_item_data_get(gli); + if (!sti) return; + st->realized_count++; + sti->live = EINA_TRUE; + if (sti->eval_job) ecore_job_del(sti->eval_job); + sti->eval_job = ecore_job_add(_store_item_eval, sti); } static void _store_genlist_item_unrealized(void *data, Evas_Object *obj __UNUSED__, void *event_info) { - Elm_Store *st = data; - Elm_Genlist_Item *gli = event_info; - Elm_Store_Item *sti = elm_genlist_item_data_get(gli); - if (!sti) return; - st->realized_count--; - sti->live = EINA_FALSE; - if (sti->eval_job) ecore_job_del(sti->eval_job); - sti->eval_job = ecore_job_add(_store_item_eval, sti); + Elm_Store *st = data; + Elm_Genlist_Item *gli = event_info; + Elm_Store_Item *sti = elm_genlist_item_data_get(gli); + if (!sti) return; + st->realized_count--; + sti->live = EINA_FALSE; + if (sti->eval_job) ecore_job_del(sti->eval_job); + sti->eval_job = ecore_job_add(_store_item_eval, sti); } static const Elm_Store_Item_Mapping * _store_item_mapping_find(Elm_Store_Item *sti, const char *part) { - const Elm_Store_Item_Mapping *m; - - for (m = sti->mapping; m; m ++) - { - if (m->type == ELM_STORE_ITEM_MAPPING_NONE) break; - if (!strcmp(part, m->part)) return m; - } - return NULL; + const Elm_Store_Item_Mapping *m; + + for (m = sti->mapping; m; m ++) + { + if (m->type == ELM_STORE_ITEM_MAPPING_NONE) break; + if (!strcmp(part, m->part)) return m; + } + return NULL; } static char * _store_item_label_get(void *data, Evas_Object *obj __UNUSED__, const char *part) { - Elm_Store_Item *sti = data; - const char *s = ""; - LKL(sti->lock); - if (sti->data) - { - const Elm_Store_Item_Mapping *m = _store_item_mapping_find(sti, part); - if (m) - { - switch (m->type) - { - case ELM_STORE_ITEM_MAPPING_LABEL: - s = *(char **)(((unsigned char *)sti->data) + m->offset); - break; - case ELM_STORE_ITEM_MAPPING_CUSTOM: - if (m->details.custom.func) - s = m->details.custom.func(sti->data, sti, part); - break; - default: - break; - } - } - } - LKU(sti->lock); - return strdup(s); + Elm_Store_Item *sti = data; + const char *s = ""; + LKL(sti->lock); + if (sti->data) + { + const Elm_Store_Item_Mapping *m = _store_item_mapping_find(sti, part); + if (m) + { + switch (m->type) + { + case ELM_STORE_ITEM_MAPPING_LABEL: + s = *(char **)(((unsigned char *)sti->data) + m->offset); + break; + case ELM_STORE_ITEM_MAPPING_CUSTOM: + if (m->details.custom.func) + s = m->details.custom.func(sti->data, sti, part); + break; + default: + break; + } + } + } + LKU(sti->lock); + return strdup(s); } static Evas_Object * _store_item_icon_get(void *data, Evas_Object *obj, const char *part) { - Elm_Store_Item *sti = data; - LKL(sti->lock); - if (sti->data) - { - const Elm_Store_Item_Mapping *m = _store_item_mapping_find(sti, part); - if (m) - { - Evas_Object *ic = NULL; - const char *s = NULL; - - switch (m->type) - { - case ELM_STORE_ITEM_MAPPING_ICON: - ic = elm_icon_add(obj); - s = *(char **)(((unsigned char *)sti->data) + m->offset); - elm_icon_order_lookup_set(ic, m->details.icon.lookup_order); - evas_object_size_hint_aspect_set(ic, - EVAS_ASPECT_CONTROL_VERTICAL, - m->details.icon.w, - m->details.icon.h); - elm_icon_smooth_set(ic, m->details.icon.smooth); - elm_icon_no_scale_set(ic, m->details.icon.no_scale); - elm_icon_scale_set(ic, - m->details.icon.scale_up, - m->details.icon.scale_down); - if (s) - { - if (m->details.icon.standard_name) - elm_icon_standard_set(ic, s); - else - elm_icon_file_set(ic, s, NULL); - } - break; - case ELM_STORE_ITEM_MAPPING_PHOTO: - ic = elm_icon_add(obj); - s = *(char **)(((unsigned char *)sti->data) + m->offset); - elm_photo_size_set(ic, m->details.photo.size); - if (s) - elm_photo_file_set(ic, s); - break; - case ELM_STORE_ITEM_MAPPING_CUSTOM: - if (m->details.custom.func) - ic = m->details.custom.func(sti->data, sti, part); - break; - default: - break; - } - LKU(sti->lock); - return ic; - } - } - LKU(sti->lock); - return NULL; + Elm_Store_Item *sti = data; + LKL(sti->lock); + if (sti->data) + { + const Elm_Store_Item_Mapping *m = _store_item_mapping_find(sti, part); + if (m) + { + Evas_Object *ic = NULL; + const char *s = NULL; + + switch (m->type) + { + case ELM_STORE_ITEM_MAPPING_ICON: + ic = elm_icon_add(obj); + s = *(char **)(((unsigned char *)sti->data) + m->offset); + elm_icon_order_lookup_set(ic, m->details.icon.lookup_order); + evas_object_size_hint_aspect_set(ic, + EVAS_ASPECT_CONTROL_VERTICAL, + m->details.icon.w, + m->details.icon.h); + elm_icon_smooth_set(ic, m->details.icon.smooth); + elm_icon_no_scale_set(ic, m->details.icon.no_scale); + elm_icon_scale_set(ic, + m->details.icon.scale_up, + m->details.icon.scale_down); + if (s) + { + if (m->details.icon.standard_name) + elm_icon_standard_set(ic, s); + else + elm_icon_file_set(ic, s, NULL); + } + break; + case ELM_STORE_ITEM_MAPPING_PHOTO: + ic = elm_icon_add(obj); + s = *(char **)(((unsigned char *)sti->data) + m->offset); + elm_photo_size_set(ic, m->details.photo.size); + if (s) + elm_photo_file_set(ic, s); + break; + case ELM_STORE_ITEM_MAPPING_CUSTOM: + if (m->details.custom.func) + ic = m->details.custom.func(sti->data, sti, part); + break; + default: + break; + } + LKU(sti->lock); + return ic; + } + } + LKU(sti->lock); + return NULL; } static void @@ -380,58 +419,58 @@ _store_item_del(void *data __UNUSED__, Evas_Object *obj __UNUSED__) static int _store_filesystem_sort_cb(void *d1, void *d2) { - Elm_Store_Item_Info *info1 = d1, *info2 = d2; - if ((!info1->sort_id) || (!info2->sort_id)) return 0; - return strcoll(info1->sort_id, info2->sort_id); + Elm_Store_Item_Info *info1 = d1, *info2 = d2; + if ((!info1->sort_id) || (!info2->sort_id)) return 0; + return strcoll(info1->sort_id, info2->sort_id); } static void _store_filesystem_list_do(void *data, Ecore_Thread *th __UNUSED__) { - Elm_Store_Filesystem *st = data; - Eina_Iterator *it; - const Eina_File_Direct_Info *finf; - Eina_List *sorted = NULL; - Elm_Store_Item_Info_Filesystem *info; - - // FIXME: need a way to abstract the open, list, feed items from list - // and maybe get initial sortable key vals etc. - it = eina_file_stat_ls(st->dir); - if (!it) return; - EINA_ITERATOR_FOREACH(it, finf) - { - Eina_Bool ok; - size_t pathsz = finf->path_length + 1; - - info = calloc(1, sizeof(Elm_Store_Item_Info_Filesystem) + pathsz); - if (!info) continue; - info->path = ((char *)info) + sizeof(Elm_Store_Item_Info_Filesystem); - memcpy(info->path, finf->path, pathsz); - ok = EINA_TRUE; - if (st->base.cb.list.func) - ok = st->base.cb.list.func(st->base.cb.list.data, &info->base); - if (ok) - { - if (!st->base.sorted) ecore_thread_feedback(th, info); - else sorted = eina_list_append(sorted, info); - } - else - { - if (info->base.sort_id) free(info->base.sort_id); - free(info); - } - if (ecore_thread_check(th)) break; - } - eina_iterator_free(it); - if (sorted) - { - sorted = eina_list_sort(sorted, 0, - EINA_COMPARE_CB(_store_filesystem_sort_cb)); - EINA_LIST_FREE(sorted, info) - { - if (!ecore_thread_check(th)) ecore_thread_feedback(th, info); - } - } + Elm_Store_Filesystem *st = data; + Eina_Iterator *it; + const Eina_File_Direct_Info *finf; + Eina_List *sorted = NULL; + Elm_Store_Item_Info_Filesystem *info; + + // FIXME: need a way to abstract the open, list, feed items from list + // and maybe get initial sortable key vals etc. + it = eina_file_stat_ls(st->dir); + if (!it) return; + EINA_ITERATOR_FOREACH(it, finf) + { + Eina_Bool ok; + size_t pathsz = finf->path_length + 1; + + info = calloc(1, sizeof(Elm_Store_Item_Info_Filesystem) + pathsz); + if (!info) continue; + info->path = ((char *)info) + sizeof(Elm_Store_Item_Info_Filesystem); + memcpy(info->path, finf->path, pathsz); + ok = EINA_TRUE; + if (st->base.cb.list.func) + ok = st->base.cb.list.func(st->base.cb.list.data, &info->base); + if (ok) + { + if (!st->base.sorted) ecore_thread_feedback(th, info); + else sorted = eina_list_append(sorted, info); + } + else + { + if (info->base.sort_id) free(info->base.sort_id); + free(info); + } + if (ecore_thread_check(th)) break; + } + eina_iterator_free(it); + if (sorted) + { + sorted = eina_list_sort(sorted, 0, + EINA_COMPARE_CB(_store_filesystem_sort_cb)); + EINA_LIST_FREE(sorted, info) + { + if (!ecore_thread_check(th)) ecore_thread_feedback(th, info); + } + } } // ************************************************************************ //// * End of separate thread function. * @@ -440,88 +479,89 @@ _store_filesystem_list_do(void *data, Ecore_Thread *th __UNUSED__) static void _store_filesystem_list_end(void *data, Ecore_Thread *th) { - Elm_Store *st = data; - if (th == st->list_th) st->list_th = NULL; + Elm_Store *st = data; + if (th == st->list_th) st->list_th = NULL; } static void _store_filesystem_list_cancel(void *data, Ecore_Thread *th) { - Elm_Store *st = data; - if (th == st->list_th) st->list_th = NULL; + Elm_Store *st = data; + if (th == st->list_th) st->list_th = NULL; } static void _store_filesystem_list_update(void *data, Ecore_Thread *th __UNUSED__, void *msg) { - Elm_Store *st = data; - Elm_Store_Item_Filesystem *sti; - Elm_Genlist_Item_Class *itc; - Elm_Store_Item_Info_Filesystem *info = msg; - - sti = calloc(1, sizeof(Elm_Store_Item_Filesystem)); - if (!sti) goto done; - LKI(sti->base.lock); - EINA_MAGIC_SET(&(sti->base), ELM_STORE_ITEM_MAGIC); - sti->base.store = st; - sti->base.data = info->base.data; - sti->base.mapping = info->base.mapping; - sti->path = eina_stringshare_add(info->path); - - itc = info->base.item_class; - if (!itc) itc = &_store_item_class; - else - { - itc->func.label_get = _store_item_label_get; - itc->func.icon_get = _store_item_icon_get; - itc->func.state_get = NULL; // FIXME: support state gets later - itc->func.del = _store_item_del; - } - - // FIXME: handle being a parent (tree) - sti->base.item = elm_genlist_item_append(st->genlist, itc, - sti/* item data */, - NULL/* parent */, - ELM_GENLIST_ITEM_NONE, - NULL/* func */, - NULL/* func data */); - st->items = eina_inlist_append(st->items, (Eina_Inlist *)sti); + Elm_Store *st = data; + Elm_Store_Item_Filesystem *sti; + Elm_Genlist_Item_Class *itc; + Elm_Store_Item_Info_Filesystem *info = msg; + + sti = calloc(1, sizeof(Elm_Store_Item_Filesystem)); + if (!sti) goto done; + LKI(sti->base.lock); + EINA_MAGIC_SET(&(sti->base), ELM_STORE_ITEM_MAGIC); + sti->base.store = st; + sti->base.data = info->base.data; + sti->base.mapping = info->base.mapping; + sti->path = eina_stringshare_add(info->path); + + itc = info->base.item_class; + if (!itc) itc = &_store_item_class; + else + { + itc->func.label_get = (GenlistItemLabelGetFunc)_store_item_label_get; + itc->func.icon_get = (GenlistItemIconGetFunc)_store_item_icon_get; + itc->func.state_get = NULL; // FIXME: support state gets later + itc->func.del = (GenlistItemDelFunc)_store_item_del; + } + + // FIXME: handle being a parent (tree) + sti->base.item = elm_genlist_item_append(st->genlist, itc, + sti/* item data */, + NULL/* parent */, + ELM_GENLIST_ITEM_NONE, + NULL/* func */, + NULL/* func data */); + st->items = eina_inlist_append(st->items, (Eina_Inlist *)sti); done: - if (info->base.sort_id) free(info->base.sort_id); - free(info); + if (info->base.sort_id) free(info->base.sort_id); + free(info); } // public api calls static Elm_Store * _elm_store_new(size_t size) { - Elm_Store *st = calloc(1, size); - EINA_SAFETY_ON_NULL_RETURN_VAL(st, NULL); - - // TODO: BEGIN - move to elm_store_init() - eina_magic_string_set(ELM_STORE_MAGIC, "Elm_Store"); - eina_magic_string_set(ELM_STORE_FILESYSTEM_MAGIC, "Elm_Store_Filesystem"); - eina_magic_string_set(ELM_STORE_ITEM_MAGIC, "Elm_Store_Item"); - // setup default item class (always the same) if list cb doesnt provide one - _store_item_class.item_style = "default"; - _store_item_class.func.label_get = _store_item_label_get; - _store_item_class.func.icon_get = _store_item_icon_get; - _store_item_class.func.state_get = NULL; // FIXME: support state gets later - _store_item_class.func.del = _store_item_del; - // TODO: END - move to elm_store_init() - - EINA_MAGIC_SET(st, ELM_STORE_MAGIC); - st->cache_max = 128; - st->fetch_thread = EINA_TRUE; - return st; + Elm_Store *st = calloc(1, size); + EINA_SAFETY_ON_NULL_RETURN_VAL(st, NULL); + + // TODO: BEGIN - move to elm_store_init() + eina_magic_string_set(ELM_STORE_MAGIC, "Elm_Store"); + eina_magic_string_set(ELM_STORE_FILESYSTEM_MAGIC, "Elm_Store_Filesystem"); + eina_magic_string_set(ELM_STORE_ITEM_MAGIC, "Elm_Store_Item"); + // setup default item class (always the same) if list cb doesnt provide one + _store_item_class.item_style = "default"; + _store_item_class.func.label_get = (GenlistItemLabelGetFunc)_store_item_label_get; + _store_item_class.func.icon_get = (GenlistItemIconGetFunc)_store_item_icon_get; + _store_item_class.func.state_get = NULL; // FIXME: support state gets later + _store_item_class.func.del = (GenlistItemDelFunc)_store_item_del; + // TODO: END - move to elm_store_init() + + EINA_MAGIC_SET(st, ELM_STORE_MAGIC); + st->cache_max = 128; + st->fetch_thread = EINA_TRUE; + st->type = 0; + return st; } #define elm_store_new(type) (type*)_elm_store_new(sizeof(type)) static void _elm_store_filesystem_free(Elm_Store *store) { - Elm_Store_Filesystem *st = (Elm_Store_Filesystem *)store; - eina_stringshare_del(st->dir); + Elm_Store_Filesystem *st = (Elm_Store_Filesystem *)store; + eina_stringshare_del(st->dir); } static void @@ -534,221 +574,1420 @@ _elm_store_filesystem_item_free(Elm_Store_Item *item) EAPI Elm_Store * elm_store_filesystem_new(void) { - Elm_Store_Filesystem *st = elm_store_new(Elm_Store_Filesystem); - EINA_SAFETY_ON_NULL_RETURN_VAL(st, NULL); + Elm_Store_Filesystem *st = elm_store_new(Elm_Store_Filesystem); + EINA_SAFETY_ON_NULL_RETURN_VAL(st, NULL); - EINA_MAGIC_SET(st, ELM_STORE_FILESYSTEM_MAGIC); - st->base.free = _elm_store_filesystem_free; - st->base.item.free = _elm_store_filesystem_item_free; + EINA_MAGIC_SET(st, ELM_STORE_FILESYSTEM_MAGIC); + st->base.free = _elm_store_filesystem_free; + st->base.item.free = _elm_store_filesystem_item_free; - return &st->base; + return &st->base; } EAPI void elm_store_free(Elm_Store *st) { - void (*item_free)(Elm_Store_Item *); - if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return; - if (st->list_th) - { - ecore_thread_cancel(st->list_th); - st->list_th = NULL; - } - eina_list_free(st->realized); - item_free = st->item.free; - while (st->items) - { - Elm_Store_Item *sti = (Elm_Store_Item *)st->items; - if (sti->eval_job) ecore_job_del(sti->eval_job); - if (sti->fetch_th) - { - ecore_thread_cancel(sti->fetch_th); - sti->fetch_th = NULL; - } - if (item_free) item_free(sti); - if (sti->data) - { - if (st->cb.unfetch.func) - st->cb.unfetch.func(st->cb.unfetch.data, sti); - sti->data = NULL; - } - LKD(sti->lock); - free(sti); - } - if (st->genlist) - { - evas_object_event_callback_del_full(st->genlist, EVAS_CALLBACK_DEL, _store_genlist_del, st); - evas_object_smart_callback_del(st->genlist, "realized", _store_genlist_item_realized); - evas_object_smart_callback_del(st->genlist, "unrealized", _store_genlist_item_unrealized); - elm_genlist_clear(st->genlist); - st->genlist = NULL; - } - if (st->free) st->free(st); - free(st); + void (*item_free)(Elm_Store_Item *); + if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return; + if (st->list_th) + { + ecore_thread_cancel(st->list_th); + st->list_th = NULL; + } + + if (!st->type) + { + eina_list_free(st->realized); + item_free = st->item.free; + while (st->items) + { + Elm_Store_Item *sti = (Elm_Store_Item *)st->items; + if (sti->eval_job) ecore_job_del(sti->eval_job); + if (sti->fetch_th) + { + ecore_thread_cancel(sti->fetch_th); + sti->fetch_th = NULL; + } + if (item_free) item_free(sti); + if (sti->data) + { + if (st->cb.unfetch.func) + st->cb.unfetch.func(st->cb.unfetch.data, sti, NULL); + sti->data = NULL; + } + LKD(sti->lock); + free(sti); + } + if (st->genlist) + { + evas_object_event_callback_del_full(st->genlist, EVAS_CALLBACK_DEL, _store_genlist_del, st); + evas_object_smart_callback_del(st->genlist, "realized", _store_genlist_item_realized); + evas_object_smart_callback_del(st->genlist, "unrealized", _store_genlist_item_unrealized); + elm_genlist_clear(st->genlist); + st->genlist = NULL; + } + if (st->free) st->free(st); + } + else + { + Eina_List *l; + Eina_List *header_list; + + EINA_LIST_FOREACH(st->header_items, l, header_list) + { + if (header_list) + { + Eina_List *in_l; + Elm_Store_Item *sti; + EINA_LIST_FOREACH(header_list, in_l, sti) + { + if (sti->data) + { + int index = elm_store_item_index_get(sti); + _item_unfetch(st, index); + } + } + free(sti); + } + } + eina_list_free(st->header_items); + + if (st->genlist) + { + evas_object_event_callback_del_full(st->genlist, EVAS_CALLBACK_DEL, _genlist_del, st); + evas_object_smart_callback_del(st->genlist, "realized", _item_realized); + evas_object_smart_callback_del(st->genlist, "unrealized", _item_unrealized); + elm_genlist_clear(st->genlist); + st->genlist = NULL; + } + } + free(st); } EAPI void elm_store_target_genlist_set(Elm_Store *st, Evas_Object *obj) { - if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return; - if (st->genlist == obj) return; - if (st->genlist) - { - evas_object_event_callback_del_full(st->genlist, EVAS_CALLBACK_DEL, _store_genlist_del, st); - evas_object_smart_callback_del(st->genlist, "realized", _store_genlist_item_realized); - evas_object_smart_callback_del(st->genlist, "unrealized", _store_genlist_item_unrealized); - elm_genlist_clear(st->genlist); - } - st->genlist = obj; - if (!st->genlist) return; - evas_object_smart_callback_add(st->genlist, "realized", _store_genlist_item_realized, st); - evas_object_smart_callback_add(st->genlist, "unrealized", _store_genlist_item_unrealized, st); - evas_object_event_callback_add(st->genlist, EVAS_CALLBACK_DEL, _store_genlist_del, st); - elm_genlist_clear(st->genlist); + if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return; + if (st->genlist == obj) return; + if (st->genlist) + { + if (!st->type) + { + evas_object_event_callback_del_full(st->genlist, EVAS_CALLBACK_DEL, _store_genlist_del, st); + evas_object_smart_callback_del(st->genlist, "realized", _store_genlist_item_realized); + evas_object_smart_callback_del(st->genlist, "unrealized", _store_genlist_item_unrealized); + } + else + { + evas_object_event_callback_del_full(st->genlist, EVAS_CALLBACK_DEL, _genlist_del, st); + evas_object_smart_callback_del(st->genlist, "realized", _item_realized); + evas_object_smart_callback_del(st->genlist, "unrealized", _item_unrealized); + } + elm_genlist_clear(st->genlist); + } + st->genlist = obj; + if (!st->genlist) return; + if (!st->type) + { + evas_object_smart_callback_add(st->genlist, "realized", _store_genlist_item_realized, st); + evas_object_smart_callback_add(st->genlist, "unrealized", _store_genlist_item_unrealized, st); + evas_object_event_callback_add(st->genlist, EVAS_CALLBACK_DEL, _store_genlist_del, st); + } + else + { + evas_object_smart_callback_add(st->genlist, "realized", _item_realized, st); + evas_object_smart_callback_add(st->genlist, "unrealized", _item_unrealized, st); + evas_object_event_callback_add(st->genlist, EVAS_CALLBACK_DEL, _genlist_del, st); + st->block_count = elm_genlist_block_count_get(st->genlist); + } + elm_genlist_clear(st->genlist); } EAPI void elm_store_filesystem_directory_set(Elm_Store *store, const char *dir) { Elm_Store_Filesystem *st = (Elm_Store_Filesystem *)store; - if (!EINA_MAGIC_CHECK(store, ELM_STORE_MAGIC)) return; - if (!EINA_MAGIC_CHECK(st, ELM_STORE_FILESYSTEM_MAGIC)) return; - if (store->list_th) - { - ecore_thread_cancel(store->list_th); - store->list_th = NULL; - } - if (!eina_stringshare_replace(&st->dir, dir)) return; - store->list_th = ecore_thread_feedback_run(_store_filesystem_list_do, - _store_filesystem_list_update, - _store_filesystem_list_end, - _store_filesystem_list_cancel, - st, EINA_TRUE); + if (!EINA_MAGIC_CHECK(store, ELM_STORE_MAGIC)) return; + if (!EINA_MAGIC_CHECK(st, ELM_STORE_FILESYSTEM_MAGIC)) return; + if (store->list_th) + { + ecore_thread_cancel(store->list_th); + store->list_th = NULL; + } + if (!eina_stringshare_replace(&st->dir, dir)) return; + store->list_th = ecore_thread_feedback_run(_store_filesystem_list_do, + _store_filesystem_list_update, + _store_filesystem_list_end, + _store_filesystem_list_cancel, + st, EINA_TRUE); } EAPI const char * elm_store_filesystem_directory_get(const Elm_Store *store) { - const Elm_Store_Filesystem *st = (const Elm_Store_Filesystem *)store; - if (!EINA_MAGIC_CHECK(store, ELM_STORE_MAGIC)) return NULL; - if (!EINA_MAGIC_CHECK(st, ELM_STORE_FILESYSTEM_MAGIC)) return NULL; - return st->dir; + const Elm_Store_Filesystem *st = (const Elm_Store_Filesystem *)store; + if (!EINA_MAGIC_CHECK(store, ELM_STORE_MAGIC)) return NULL; + if (!EINA_MAGIC_CHECK(st, ELM_STORE_FILESYSTEM_MAGIC)) return NULL; + return st->dir; } EAPI void elm_store_cache_set(Elm_Store *st, int max) { - if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return; - if (max < 0) max = 0; - st->cache_max = max; - _store_cache_trim(st); + if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return; + if (max < 0) max = 0; + st->cache_max = max; + if(!st->type) _store_cache_trim(st); } EAPI int elm_store_cache_get(const Elm_Store *st) { - if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return 0; - return st->cache_max; + if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return 0; + return st->cache_max; } EAPI void elm_store_list_func_set(Elm_Store *st, Elm_Store_Item_List_Cb func, const void *data) { - if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return; - st->cb.list.func = func; - st->cb.list.data = (void *)data; + if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return; + st->cb.list.func = func; + st->cb.list.data = (void *)data; } EAPI void elm_store_fetch_func_set(Elm_Store *st, Elm_Store_Item_Fetch_Cb func, const void *data) { - if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return; - st->cb.fetch.func = func; - st->cb.fetch.data = (void *)data; + if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return; + st->cb.fetch.func = func; + st->cb.fetch.data = (void *)data; } EAPI void elm_store_fetch_thread_set(Elm_Store *st, Eina_Bool use_thread) { - if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return; - st->fetch_thread = !!use_thread; + if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return; + st->fetch_thread = !!use_thread; } EAPI Eina_Bool elm_store_fetch_thread_get(const Elm_Store *st) { - if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return EINA_FALSE; - return st->fetch_thread; + if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return EINA_FALSE; + return st->fetch_thread; } EAPI void elm_store_unfetch_func_set(Elm_Store *st, Elm_Store_Item_Unfetch_Cb func, const void *data) { - if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return; - st->cb.unfetch.func = func; - st->cb.unfetch.data = (void *)data; + if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return; + st->cb.unfetch.func = func; + st->cb.unfetch.data = (void *)data; } EAPI void elm_store_sorted_set(Elm_Store *st, Eina_Bool sorted) { - if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return; - st->sorted = sorted; + if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return; + st->sorted = sorted; } EAPI Eina_Bool elm_store_sorted_get(const Elm_Store *st) { - if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return EINA_FALSE; - return st->sorted; + if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return EINA_FALSE; + return st->sorted; } EAPI void elm_store_item_data_set(Elm_Store_Item *sti, void *data) { - if (!EINA_MAGIC_CHECK(sti, ELM_STORE_ITEM_MAGIC)) return; - LKL(sti->lock); - sti->data = data; - LKU(sti->lock); + if (!EINA_MAGIC_CHECK(sti, ELM_STORE_ITEM_MAGIC)) return; + LKL(sti->lock); + sti->data = data; + LKU(sti->lock); } EAPI void * elm_store_item_data_get(Elm_Store_Item *sti) { - if (!EINA_MAGIC_CHECK(sti, ELM_STORE_ITEM_MAGIC)) return NULL; - void *d; - LKL(sti->lock); - d = sti->data; - LKU(sti->lock); - return d; + if (!EINA_MAGIC_CHECK(sti, ELM_STORE_ITEM_MAGIC)) return NULL; + void *d; + LKL(sti->lock); + d = sti->data; + LKU(sti->lock); + return d; } EAPI const Elm_Store * elm_store_item_store_get(const Elm_Store_Item *sti) { - if (!EINA_MAGIC_CHECK(sti, ELM_STORE_ITEM_MAGIC)) return NULL; - // dont need lock - return sti->store; + if (!EINA_MAGIC_CHECK(sti, ELM_STORE_ITEM_MAGIC)) return NULL; + // dont need lock + return sti->store; } EAPI const Elm_Genlist_Item * elm_store_item_genlist_item_get(const Elm_Store_Item *sti) { - if (!EINA_MAGIC_CHECK(sti, ELM_STORE_ITEM_MAGIC)) return NULL; - // dont need lock - return sti->item; + if (!EINA_MAGIC_CHECK(sti, ELM_STORE_ITEM_MAGIC)) return NULL; + // dont need lock + return sti->item; } EAPI const char * elm_store_item_filesystem_path_get(const Elm_Store_Item *item) { - Elm_Store_Item_Filesystem *sti = (Elm_Store_Item_Filesystem *)item; - Elm_Store_Filesystem *st; - if (!EINA_MAGIC_CHECK(item, ELM_STORE_ITEM_MAGIC)) return NULL; - if (!EINA_MAGIC_CHECK(item->store, ELM_STORE_MAGIC)) return NULL; - /* ensure we're dealing with filesystem item */ - st = (Elm_Store_Filesystem *)item->store; - if (!EINA_MAGIC_CHECK(st, ELM_STORE_FILESYSTEM_MAGIC)) return NULL; - // dont need lock - return sti->path; + Elm_Store_Item_Filesystem *sti = (Elm_Store_Item_Filesystem *)item; + Elm_Store_Filesystem *st; + if (!EINA_MAGIC_CHECK(item, ELM_STORE_ITEM_MAGIC)) return NULL; + if (!EINA_MAGIC_CHECK(item->store, ELM_STORE_MAGIC)) return NULL; + /* ensure we're dealing with filesystem item */ + st = (Elm_Store_Filesystem *)item->store; + if (!EINA_MAGIC_CHECK(st, ELM_STORE_FILESYSTEM_MAGIC)) return NULL; + // dont need lock + return sti->path; +} + +// TODO: BEGIN -DBsystem store + +static Elm_Store * +_store_init(size_t size) +{ + Elm_Store *st = calloc(1, size); + if (!st) return NULL; + + eina_magic_string_set(ELM_STORE_MAGIC, "Elm_Store"); + eina_magic_string_set(ELM_STORE_FILESYSTEM_MAGIC, "Elm_Store_Filesystem"); + eina_magic_string_set(ELM_STORE_ITEM_MAGIC, "Elm_Store_Item"); + eina_magic_string_set(ELM_STORE_DBSYSTEM_MAGIC, "Elm_Store_DBsystem"); + + _store_item_class.item_style = "default"; + _store_item_class.func.label_get = (GenlistItemLabelGetFunc)_item_label_get; + _store_item_class.func.icon_get = (GenlistItemIconGetFunc)_item_icon_get; + _store_item_class.func.state_get = NULL; + _store_item_class.func.del = (GenlistItemDelFunc)_item_del; + + EINA_MAGIC_SET(st, ELM_STORE_MAGIC); + st->cache_max = CACHE_COUNT; + st->current_top_index = 0; + st->start_fetch_index = 0; + st->end_fetch_index = st->cache_max - 1; + st->live = EINA_TRUE; + st->multi_load = EINA_FALSE; + st->total_count = 0; + st->fetch_thread = EINA_FALSE; + st->type = 1; + return st; +} + +#define _store_new(type) (type *)_store_init(sizeof(type)) + +static void +_genlist_del(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__) +{ + EINA_SAFETY_ON_NULL_RETURN(data); + Elm_Store *st = data; + if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return; + + elm_store_free(st); +} + +static void +_store_fetch_do(void *data, Ecore_Thread *th __UNUSED__) +{ + Elm_Store_Item *sti = data; + sti->store->cb.fetch.func(sti->store->cb.fetch.data, sti, sti->item_info); + sti->fetched = EINA_TRUE; +} + +static void +_store_fetch_end(void *data, Ecore_Thread *th) +{ + Elm_Store_Item *sti = data; + if (sti->data) elm_genlist_item_update(sti->item); + if (th == sti->fetch_th) sti->fetch_th = NULL; +} + +static void +_store_fetch_cancel(void *data, Ecore_Thread *th) +{ + Elm_Store_Item *sti = data; + if (sti->data) elm_genlist_item_update(sti->item); + if (th == sti->fetch_th) sti->fetch_th = NULL; +} + +static Elm_Store_Item * +_item_fetch(Elm_Store *st, int index) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(st,NULL); + Elm_Store_Item *sti; + + int in_index = 0; + Eina_List *l; + Eina_List *header_list; + + EINA_LIST_FOREACH(st->header_items, l, header_list) + { + if ((in_index + eina_list_count(header_list)) > index) + { + sti = eina_list_nth(header_list, index - in_index); + if ((!sti->fetched) && st->cb.fetch.func && (!sti->fetch_th)) + { + if (st->fetch_thread) + { + sti->fetch_th = ecore_thread_run(_store_fetch_do, + _store_fetch_end, + _store_fetch_cancel, + sti); + } + else + { + st->cb.fetch.func(st->cb.fetch.data, sti, sti->item_info); + sti->fetched = EINA_TRUE; + } + } + return sti; + } + else + { + in_index = in_index + eina_list_count(header_list); + } + } + return NULL; +} + +static Elm_Store_Item * +_item_unfetch(Elm_Store *st, int index) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(st,NULL); + Elm_Store_Item *sti; + + int in_index = 0; + Eina_List *l; + Eina_List *header_list; + + EINA_LIST_FOREACH(st->header_items, l, header_list) + { + if ((in_index + eina_list_count(header_list)) > index) + { + sti = eina_list_nth(header_list, index - in_index); + if (sti->fetched && st->cb.unfetch.func) + { + if (sti->fetch_th) + { + ecore_thread_cancel(sti->fetch_th); + sti->fetch_th = NULL; + } + + st->cb.unfetch.func(st->cb.unfetch.data, sti, sti->item_info); + sti->data = NULL; + sti->fetched = EINA_FALSE; + } + return sti; + } + else + { + in_index = in_index + eina_list_count(header_list); + } + } + return NULL; +} + +static const Elm_Store_Item_Mapping * +_item_mapping_find(Elm_Store_Item *sti, const char *part) +{ + const Elm_Store_Item_Mapping *m; + + for (m = sti->item_info->mapping; m; m++) + { + if (m->type == ELM_STORE_ITEM_MAPPING_NONE) break; + if (!strcmp(part, m->part)) return m; + } + return NULL; +} + +static char * +_item_label_get(void *data, Evas_Object *obj __UNUSED__, const char *part) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(data, strdup("")); + Elm_Store_Item *sti = data; + + if (sti->item) + { + if (sti->fetched == EINA_FALSE) + { + if (!sti->data) + { + int index = elm_store_item_index_get(sti); + if (sti->store->start_fetch_index > index) + { + int diff = sti->store->start_fetch_index - index; + int loop; + for (loop = 1; loop <= diff; loop++) + { + _item_unfetch(sti->store, sti->store->end_fetch_index); + sti->store->end_fetch_index--; + _item_fetch(sti->store, (sti->store->start_fetch_index - loop)); + } + sti->store->start_fetch_index = index; + } + else if (index > sti->store->end_fetch_index) + { + int diff = index - sti->store->end_fetch_index; + int loop; + for (loop = 1; loop <= diff; loop++) + { + _item_unfetch(sti->store, sti->store->start_fetch_index); + sti->store->start_fetch_index++; + _item_fetch(sti->store, (sti->store->end_fetch_index + loop)); + } + sti->store->end_fetch_index = index; + } + } + } + + if (sti->data) + { + const char *s = ""; + const Elm_Store_Item_Mapping *m = _item_mapping_find(sti, part); + if (m) + { + switch (m->type) + { + case ELM_STORE_ITEM_MAPPING_LABEL: + s = *(char **)(((unsigned char *)sti->data) + m->offset); + break; + + case ELM_STORE_ITEM_MAPPING_CUSTOM: + if (m->details.custom.func) + s = m->details.custom.func(sti->data, sti, part); + break; + + default: + break; + } + if (s) + { + return strdup(s); + } + else + { + return NULL; + } + } + } + } + return NULL; +} + +static Evas_Object * +_item_icon_get(void *data, Evas_Object *obj, const char *part) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(data,NULL); + Elm_Store_Item *sti = data; + EINA_SAFETY_ON_NULL_RETURN_VAL(sti,NULL); + + if (sti->item) + { + if (sti->data) + { + const Elm_Store_Item_Mapping *m = _item_mapping_find(sti, part); + if (m) + { + Evas_Object *ic = NULL; + const char *s = NULL; + + switch (m->type) + { + case ELM_STORE_ITEM_MAPPING_ICON: + ic = elm_icon_add(obj); + s = *(char **)(((unsigned char *)sti->data) + m->offset); + elm_icon_order_lookup_set(ic, m->details.icon.lookup_order); + evas_object_size_hint_aspect_set(ic, + EVAS_ASPECT_CONTROL_VERTICAL, + m->details.icon.w, + m->details.icon.h); + elm_icon_smooth_set(ic, m->details.icon.smooth); + elm_icon_no_scale_set(ic, m->details.icon.no_scale); + elm_icon_scale_set(ic, + m->details.icon.scale_up, + m->details.icon.scale_down); + + if (s) + { + if (m->details.icon.standard_name) + elm_icon_standard_set(ic, s); + else + elm_icon_file_set(ic, s, NULL); + } + break; + + case ELM_STORE_ITEM_MAPPING_PHOTO: + ic = elm_icon_add(obj); + s = *(char **)(((unsigned char *)sti->data) + m->offset); + elm_photo_size_set(ic, m->details.photo.size); + if (s) + elm_photo_file_set(ic, s); + break; + + case ELM_STORE_ITEM_MAPPING_CUSTOM: + if (m->details.custom.func) + ic = m->details.custom.func(sti->data, sti, part); + break; + + default: + break; + } + return ic; + } + } + } + return NULL; +} + +static void +_item_realized(void *data, Evas_Object *obj __UNUSED__, void *event_info) +{ + EINA_SAFETY_ON_NULL_RETURN(data); + EINA_SAFETY_ON_NULL_RETURN(event_info); + Elm_Store *st = data; + Elm_Genlist_Item *gli = event_info; + Elm_Store_Item *sti = elm_genlist_item_data_get(gli); + + EINA_SAFETY_ON_NULL_RETURN(sti); + + int index = elm_store_item_index_get(sti); + + if (st->fetch_thread) + { + if ((st->start_fetch_index <= index) && (index <= st->end_fetch_index)) + { + int middle_index = sti->store->start_fetch_index + (sti->store->cache_max) / 2; + + if ((middle_index < index) && (sti->store->end_fetch_index < sti->store->total_count)) + { + int diff = index - middle_index; + int loop; + for (loop = 0; loop < diff; loop++) + { + _item_unfetch(st, sti->store->start_fetch_index); + sti->store->start_fetch_index++; + _item_fetch(st, (sti->store->end_fetch_index + 1)); + sti->store->end_fetch_index++; + } + } + else if ((middle_index > index) && (sti->store->start_fetch_index > 0)) + { + int diff = st->current_top_index - index; + int loop; + for (loop = 0; loop < diff; loop++) + { + _item_unfetch(st, sti->store->end_fetch_index); + sti->store->end_fetch_index--; + _item_fetch(st, (sti->store->start_fetch_index - 1)); + sti->store->start_fetch_index--; + } + } + else { + if ((!sti->fetched)) + { + _item_fetch(st, index); + } + } + } + } + + if ((st->current_top_index > index)) + { + st->current_top_index = index; + } + else if ((st->current_top_index + SCREEN_ITEM_COUNT) < index) + { + st->current_top_index = st->current_top_index + (index - (st->current_top_index + SCREEN_ITEM_COUNT)); + } + + // TODO: fix the item when it disposed quickly before call the label get. as example, get_more_btn in email +} + +static void +_item_unrealized(void *data, Evas_Object *obj __UNUSED__, void *event_info) +{ + EINA_SAFETY_ON_NULL_RETURN(data); + EINA_SAFETY_ON_NULL_RETURN(event_info); + Elm_Genlist_Item *gli = event_info; + Elm_Store_Item *sti = elm_genlist_item_data_get(gli); + EINA_SAFETY_ON_NULL_RETURN(sti); +} + +static void +_item_del(void *data, Evas_Object *obj __UNUSED__) +{ + EINA_SAFETY_ON_NULL_RETURN(data); + Elm_Store_Item *sti = data; + EINA_SAFETY_ON_NULL_RETURN(sti); + if (!EINA_MAGIC_CHECK(sti, ELM_STORE_ITEM_MAGIC)) return; + elm_store_item_del(sti); +} + +static void +_list_do(void *data, Ecore_Thread *th __UNUSED__) +{ + EINA_SAFETY_ON_NULL_RETURN(data); + Elm_Store *st = data; + if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return; + + if (st->multi_load == EINA_TRUE) + { + Elm_Store_Item_Info *item_info; + Eina_Bool ok = EINA_FALSE; + int loop; + for (loop = 0; loop < st->item_count; loop++) + { + item_info = calloc(1, sizeof(Elm_Store_Item_Info)); + if (!item_info) return; + item_info->index = loop; + + if (st->cb.list.func) + { + ok = st->cb.list.func(st->cb.list.data, item_info); + } + if (ok) ecore_thread_feedback(th, item_info); + else free(item_info); + if (ecore_thread_check(th)) break; + } + } +} + +static void +_list_update(void *data, Ecore_Thread *th __UNUSED__, void *msg) +{ + EINA_SAFETY_ON_NULL_RETURN(data); + EINA_SAFETY_ON_NULL_RETURN(msg); + Elm_Store *st = data; + Elm_Store_Item_Info *info = msg; + + elm_store_item_add(st, info); +} + +static void +_list_end(void *data, Ecore_Thread *th) +{ + EINA_SAFETY_ON_NULL_RETURN(data); + EINA_SAFETY_ON_NULL_RETURN(th); + Elm_Store *st = data; + + if (th == st->list_th) + { + ecore_thread_cancel(st->list_th); + st->list_th = NULL; + } +} + +static void +_list_cancel(void *data, Ecore_Thread *th) +{ + EINA_SAFETY_ON_NULL_RETURN(data); + EINA_SAFETY_ON_NULL_RETURN(th); + Elm_Store *st = data; + + if (th == st->list_th) + { + ecore_thread_cancel(st->list_th); + st->list_th = NULL; + } +} + +static Elm_Store_Item * +_item_get(const Elm_Store *st, const int index) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(st,NULL); + if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return NULL; + + if (st->live) + { + int in_index = 0; + + Elm_Store_Item *sti; + Eina_List *l; + Eina_List *header_list; + + EINA_LIST_FOREACH(st->header_items, l, header_list) + { + if ((in_index + eina_list_count(header_list)) > index) + { + sti = eina_list_nth(header_list, index - in_index); + return sti; + } + else + { + in_index = in_index + eina_list_count(header_list); + } + } + } + return NULL; +} + +static void +_item_select_cb(void *data, Evas_Object *obj, void *event_info) +{ + EINA_SAFETY_ON_NULL_RETURN(event_info); + + const Elm_Genlist_Item *it = (Elm_Genlist_Item *)event_info; + Elm_Store_Item *sti = elm_genlist_item_data_get(it); + if (!EINA_MAGIC_CHECK(sti, ELM_STORE_ITEM_MAGIC)) return; + + if (sti->store->cb.item_select.func) + { + sti->store->cb.item_select.func(sti->store->cb.item_select.data, sti); + } +} + +static void +_group_item_append(Elm_Store_Item *sti, Elm_Genlist_Item_Class *itc) +{ + EINA_SAFETY_ON_NULL_RETURN(sti); + if (!EINA_MAGIC_CHECK(sti, ELM_STORE_ITEM_MAGIC)) return; + + if (sti->store->header_items) + { + Eina_Bool header_add = EINA_TRUE; + Eina_List *l; + Eina_List *header_list; + + EINA_LIST_FOREACH(sti->store->header_items, l, header_list) + { + Elm_Store_Item *item = eina_list_nth(header_list, 0); + + if (item->item_info->group_index == sti->item_info->group_index) + { + header_add = EINA_FALSE; + break; + } + } + if (header_add) + { + Eina_List *new_header_list = NULL; + sti->item_info->index = 0; + new_header_list = eina_list_append(new_header_list, sti); + + Eina_Bool last_header = EINA_TRUE; + Eina_List *l; + Eina_List *header_list; + + EINA_LIST_FOREACH(sti->store->header_items, l, header_list) + { + Elm_Store_Item *temp_sti = eina_list_nth(header_list, 0); + + if (temp_sti->item_info->group_index > sti->item_info->group_index) + { + sti->store->header_items = eina_list_prepend_relative(sti->store->header_items, new_header_list, header_list); + sti->item = elm_genlist_item_insert_before(sti->store->genlist, + itc, + sti, + NULL, + temp_sti->item, + ELM_GENLIST_ITEM_GROUP, + (Evas_Smart_Cb)sti->store->cb.item_select.func, + (void *)sti->store->cb.item_select.data); + elm_store_item_update(sti->store, sti); + last_header = EINA_FALSE; + break; + } + } + if (last_header) + { + sti->store->header_items = eina_list_append(sti->store->header_items, new_header_list); + sti->item = elm_genlist_item_append(sti->store->genlist, + itc, + sti, + NULL, + ELM_GENLIST_ITEM_GROUP, + _item_select_cb, + NULL); + elm_store_item_update(sti->store, sti); + } + } + } + else + { + Eina_List *header_list = NULL; + sti->item_info->index = 0; + header_list = eina_list_append(header_list, sti); + sti->store->header_items = eina_list_append(sti->store->header_items, header_list); + sti->item = elm_genlist_item_append(sti->store->genlist, + itc, + sti, + NULL, + ELM_GENLIST_ITEM_GROUP, + _item_select_cb, + NULL); + elm_store_item_update(sti->store, sti); + } +} + +static void +_normal_item_append(Elm_Store_Item *sti, Elm_Genlist_Item_Class *itc) +{ + EINA_SAFETY_ON_NULL_RETURN(sti); + if (!EINA_MAGIC_CHECK(sti, ELM_STORE_ITEM_MAGIC)) return; + Elm_Store *st = sti->store; + + if (sti->item_info->rec_item == EINA_TRUE) + { + if (sti->item_info->group_index == sti->item_info->pre_group_index) + { + elm_store_item_update(st, sti); + } + else + { + Eina_List *l; + Eina_List *header_list; + + EINA_LIST_FOREACH(st->header_items, l, header_list) + { + Elm_Store_Item *header_item = eina_list_nth(header_list, 0); + + if (header_item->item_info->group_index == sti->item_info->pre_group_index) + { + Elm_Store_Item *last_sti = eina_list_nth(header_list, eina_list_count(header_list) - 1); + + if (last_sti->data) + { + int index = elm_store_item_index_get(last_sti); + _item_unfetch(st, index); + } + header_list = eina_list_remove(header_list, last_sti); + + if (!header_list) + { + st->header_items = eina_list_remove(st->header_items, header_list); + eina_list_free(header_list); + } + elm_genlist_item_del(last_sti->item); + + if (eina_list_count(header_list) == 1) + { + Elm_Store_Item *temp_sti = eina_list_nth(header_list, 0); + if (temp_sti->item_info->item_type == ELM_GENLIST_ITEM_GROUP) + { + if (temp_sti->data) + { + int index = elm_store_item_index_get(temp_sti); + _item_unfetch(st, index); + } + header_list = eina_list_remove(header_list, temp_sti); + st->header_items = eina_list_remove(st->header_items, header_list); + eina_list_free(header_list); + elm_genlist_item_del(temp_sti->item); + } + } + } + else if (header_item->item_info->group_index == sti->item_info->group_index) + { + sti->item_info->index = eina_list_count(header_list); + Elm_Store_Item *last_sti = eina_list_nth(header_list, eina_list_count(header_list) - 1); + header_list = eina_list_append(header_list, sti); + sti->item = elm_genlist_item_insert_after(st->genlist, + itc, + sti, + header_item->item, + last_sti->item, + ELM_GENLIST_ITEM_NONE, + (Evas_Smart_Cb)st->cb.item_select.func, + (void *)st->cb.item_select.data); + elm_store_item_update(st, sti); + } + } + } + } + else + { + if (st->header_items) + { + Eina_Bool normal_add = EINA_TRUE; + Eina_List *l; + Eina_List *header_list; + + EINA_LIST_FOREACH(st->header_items, l, header_list) + { + if (header_list) + { + Elm_Store_Item *header_item = eina_list_nth(header_list, 0); + + if (header_item->item_info->group_index == sti->item_info->group_index) + { + sti->item_info->index = eina_list_count(header_list); + Elm_Store_Item *last_sti = eina_list_nth(header_list, eina_list_count(header_list) - 1); + header_list = eina_list_append(header_list, sti); + sti->item = elm_genlist_item_insert_after(st->genlist, + itc, + sti, + header_item->item, + last_sti->item, + ELM_GENLIST_ITEM_NONE, + (Evas_Smart_Cb)st->cb.item_select.func, + (void *)st->cb.item_select.data); + elm_store_item_update(st, sti); + normal_add = EINA_FALSE; + break; + } + } + } + if (normal_add) + { + Eina_List *new_header_list = NULL; + sti->item_info->index = 0; + new_header_list = eina_list_append(new_header_list, sti); + st->header_items = eina_list_append(st->header_items, new_header_list); + sti->item = elm_genlist_item_append(st->genlist, + itc, + sti, + NULL, + ELM_GENLIST_ITEM_NONE, + _item_select_cb, + NULL); + elm_store_item_update(st, sti); + } + } + else + { + if (st->live) + { + Eina_List *header_list = NULL; + sti->item_info->index = 0; + header_list = eina_list_append(header_list, sti); + st->header_items = eina_list_append(st->header_items, header_list); + sti->item = elm_genlist_item_append(st->genlist, + itc, + sti, + NULL, + ELM_GENLIST_ITEM_NONE, + _item_select_cb, + NULL); + elm_store_item_update(st, sti); + } + } + } +} + +static void +_item_free(Elm_Store_Item *sti) +{ + if (!EINA_MAGIC_CHECK(sti, ELM_STORE_ITEM_MAGIC)) return; + elm_store_item_del(sti); +} + +static void +_store_free(Elm_Store *st) +{ + if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return; + elm_store_free(st); +} + +/** + * Add a new dbsystem Store object + * + * @return The new object or NULL if it cannot be created + * + * @ingroup Store + */ +EAPI Elm_Store * +elm_store_dbsystem_new(void) +{ + Elm_Store_DBsystem *std = _store_new(Elm_Store_DBsystem); + EINA_SAFETY_ON_NULL_RETURN_VAL(std, NULL); + + EINA_MAGIC_SET(std, ELM_STORE_DBSYSTEM_MAGIC); + std->base.free = _store_free; + std->base.item.free = _item_free; + return &std->base; +} + +/** + * Sets the item count of a store + * + * @param st The store object + * @param count The item count of an store + * + * @ingroup Store + */ +EAPI void +elm_store_item_count_set(Elm_Store *st, int count) +{ + EINA_SAFETY_ON_NULL_RETURN(st); + if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return; + + st->item_count = count; + if (count > 0) + { + st->multi_load = EINA_TRUE; + } + else + { + st->multi_load = EINA_FALSE; + } +} + +/** + * Get the item index that included header items + * + * @param sti The store item object + * @return The item index in genlist + * + * @ingroup Store + */ +EAPI int +elm_store_item_index_get(const Elm_Store_Item *sti) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(sti, -1); + if (!EINA_MAGIC_CHECK(sti, ELM_STORE_ITEM_MAGIC)) return -1; + + if (sti->store->live) + { + int index = 0; + Eina_List *l; + Eina_List *header_list; + + EINA_LIST_FOREACH(sti->store->header_items, l, header_list) + { + if (header_list) + { + Elm_Store_Item *temp_sti = eina_list_nth(header_list, 0); + if (sti->item_info->group_index == temp_sti->item_info->group_index) + { + index = index + sti->item_info->index; + break; + } + else + { + index = index + eina_list_count(header_list); + } + } + } + return index; + } + else + { + return -1; + } +} + +/** + * Sets the select func that select the state of a list item whether true or false + * + * @param st The store object + * @param func The select cb function of an store + * @param data The new data pointer to set + * + * @ingroup Store + */ +EAPI void +elm_store_item_select_func_set(Elm_Store *st, Elm_Store_Item_Select_Cb func, const void *data) +{ + EINA_SAFETY_ON_NULL_RETURN(st); + if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return; + + st->cb.item_select.func = func; + st->cb.item_select.data = (void *)data; +} + +/** + * Sets the sort func that sort the item with a next in the list + * + * @param st The store object + * @param func The sort cb function of an store + * @param data The new data pointer to set + * + * @ingroup Store + */ +EAPI void +elm_store_item_sort_func_set(Elm_Store *st, Elm_Store_Item_Sort_Cb func, const void *data) +{ + EINA_SAFETY_ON_NULL_RETURN(st); + if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return; + + st->cb.item_sort.func = func; + st->cb.item_sort.data = (void *)data; } + +/** + * Get the item index of real data that don't included header items + * + * @param sti The store item object + * @return The real item index + * + * @ingroup Store + */ +EAPI int +elm_store_item_data_index_get(const Elm_Store_Item *sti) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(sti, -1); + if (!EINA_MAGIC_CHECK(sti, ELM_STORE_ITEM_MAGIC)) return -1; + + if (sti->store->live) + { + if (sti->item_info->item_type == ELM_GENLIST_ITEM_NONE) + { + int index = 0; + int header_count = 0; + Eina_List *l; + Eina_List *header_list; + + EINA_LIST_FOREACH(sti->store->header_items, l, header_list) + { + + if (header_list) + { + Elm_Store_Item *temp_sti = eina_list_nth(header_list, 0); + + if (temp_sti->item_info->item_type == ELM_GENLIST_ITEM_GROUP) + { + header_count++; + } + + if (sti->item_info->group_index == temp_sti->item_info->group_index) + { + index = index + sti->item_info->index - header_count; + break; + } + else + { + index = index + eina_list_count(header_list); + } + } + } + return index; + } + else + { + return -1; + } + } + else + { + return -1; + } +} + +/** + * Get the DB pointer of an item + * + * @param sti The store item object + * @return The DB pointer of item + * + * @ingroup Store + */ +EAPI void * +elm_store_dbsystem_db_get(const Elm_Store_Item *sti) +{ + if (!EINA_MAGIC_CHECK(sti, ELM_STORE_ITEM_MAGIC)) return NULL; + + const Elm_Store_DBsystem *std = (const Elm_Store_DBsystem *)sti->store; + if (!EINA_MAGIC_CHECK(sti->store, ELM_STORE_MAGIC)) return NULL; + if (!EINA_MAGIC_CHECK(std, ELM_STORE_DBSYSTEM_MAGIC)) return NULL; + return std->p_db; +} + +/** + * Set the DB pointer of an item + * + * @param sti The store item object + * @parm p_db The DB pointer of item + * + * @ingroup Store + */ +EAPI void +elm_store_dbsystem_db_set(Elm_Store *store, void *p_db) +{ + Elm_Store_DBsystem *std = (Elm_Store_DBsystem *)store; + if (!EINA_MAGIC_CHECK(store, ELM_STORE_MAGIC)) return; + if (!EINA_MAGIC_CHECK(std, ELM_STORE_DBSYSTEM_MAGIC)) return; + + std->p_db = p_db; + + if (store->list_th) + { + ecore_thread_cancel(store->list_th); + store->list_th = NULL; + } + store->list_th = ecore_thread_feedback_run(_list_do, _list_update, _list_end, _list_cancel, store, EINA_TRUE); +} + +/** + * Append the item to the genlist + * + * @param st The store object + * @param info The store item info dbsystem object + * @return The item of store + * + * @ingroup Store + */ +EAPI Elm_Store_Item * +elm_store_item_add(Elm_Store *st, Elm_Store_Item_Info *info) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(st, NULL); + if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return NULL; + EINA_SAFETY_ON_NULL_RETURN_VAL(info, NULL); + Elm_Store_Item *sti; + Elm_Genlist_Item_Class *itc; + + sti = calloc(1, sizeof(Elm_Store_Item)); + if (!sti) return NULL; + EINA_MAGIC_SET(sti, ELM_STORE_ITEM_MAGIC); + + sti->store = st; + st->total_count++; + + sti->item_info = info; + + itc = info->item_class; + if (!itc) itc = &_store_item_class; + else + { + itc->func.label_get = (GenlistItemLabelGetFunc)_item_label_get; + itc->func.icon_get = (GenlistItemIconGetFunc)_item_icon_get; + itc->func.state_get = NULL; + itc->func.del = NULL; + } + + if (st->live) + { + if (sti->item_info->item_type == ELM_GENLIST_ITEM_GROUP) + { + _group_item_append(sti, itc); + } + else + { + _normal_item_append(sti, itc); + } + return sti; + } + else + { + return NULL; + } +} + +/** + * Realize the visible items to the screen + * + * @param st The store object + * + * @ingroup Store + */ +EAPI void +elm_store_visible_items_update(Elm_Store *st) +{ + EINA_SAFETY_ON_NULL_RETURN(st); + if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return; + + int loop; + for (loop = st->current_top_index; loop < (st->current_top_index + st->block_count); loop++) + { + Elm_Store_Item *temp_sti = _item_get(st, loop); + if (temp_sti) + { + if (temp_sti->fetched) + { + _item_unfetch(st, loop); + } + _item_fetch(st, loop); + if (temp_sti->data) elm_genlist_item_update(temp_sti->item); + + if (!st->fetch_thread) + { + if (temp_sti->data) elm_genlist_item_update(temp_sti->item); + } + } + else + { + break; + } + } +} + +/** + * Realize the item to the screen + * + * @param st The store object + * @param sti The store item object + * + * @ingroup Store + */ +EAPI void +elm_store_item_update(Elm_Store *st, Elm_Store_Item *sti) +{ + EINA_SAFETY_ON_NULL_RETURN(st); + EINA_SAFETY_ON_NULL_RETURN(sti); + if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return; + if (!EINA_MAGIC_CHECK(sti, ELM_STORE_ITEM_MAGIC)) return; + + int index = elm_store_item_index_get(sti); + + if (sti->fetched) + { + _item_unfetch(st, index); + } + _item_fetch(st, index); + if (sti->data) elm_genlist_item_update(sti->item); + + if (!st->fetch_thread) + { + if (sti->data) elm_genlist_item_update(sti->item); + } +} + +/** + * Delete the item of genlist + * + * @param sti The store item object + * + * @ingroup Store + */ +EAPI void +elm_store_item_del(Elm_Store_Item *sti) +{ + EINA_SAFETY_ON_NULL_RETURN(sti); + if (!EINA_MAGIC_CHECK(sti, ELM_STORE_ITEM_MAGIC)) return; + + sti->store->total_count--; + + Eina_List *l; + Eina_List *header_list; + + EINA_LIST_FOREACH(sti->store->header_items, l, header_list) + { + + if (header_list) + { + Elm_Store_Item *item = eina_list_nth(header_list, 0); + + if (item->item_info->group_index == sti->item_info->group_index) + { + Eina_List *in_l; + Elm_Store_Item *temp_sti; + EINA_LIST_FOREACH(header_list, in_l, temp_sti) + { + if (temp_sti->item_info->index == sti->item_info->index) + { + if (temp_sti->data) + { + int index = elm_store_item_index_get(temp_sti); + _item_unfetch(sti->store, index); + } + header_list = eina_list_remove(header_list, temp_sti); + if (!header_list) + { + sti->store->header_items = eina_list_remove(sti->store->header_items, header_list); + } + elm_genlist_item_del(temp_sti->item); + } + } + } + } + } +} + +// TODO: END -DBsystem store + -- 2.7.4