#ifdef HAVE_CONFIG_H # include #endif #include #include #include #include #include "ecore_internal.h" typedef struct _Efl_Container_Property_Data Efl_Container_Property_Data; typedef struct _Efl_Container_Model_Data Efl_Container_Model_Data; struct _Efl_Container_Property_Data { Eina_Stringshare *name; const Eina_Value_Type *type; Eina_Array *values; }; struct _Efl_Container_Model_Data { Efl_Container_Model_Data *parent; Eina_Hash *properties; // All properties value for children unsigned int children_count; }; static void _property_values_free(Eina_Array *values) { Eina_Value *v; while ((v = eina_array_pop(values))) eina_value_free(v); eina_array_free(values); } static void _property_data_free_cb(void *data) { Efl_Container_Property_Data *cpd = data; eina_stringshare_del(cpd->name); _property_values_free(cpd->values); free(cpd); } static Efl_Object * _efl_container_model_efl_object_constructor(Eo *obj, Efl_Container_Model_Data *sd) { Eo *parent; obj = efl_constructor(efl_super(obj, EFL_CONTAINER_MODEL_CLASS)); if (!obj) return NULL; parent = efl_parent_get(obj); if (efl_isa(parent, EFL_CONTAINER_MODEL_CLASS)) sd->parent = efl_data_scope_get(parent, EFL_CONTAINER_MODEL_CLASS); sd->properties = eina_hash_stringshared_new(_property_data_free_cb); return obj; } static Efl_Object * _efl_container_model_efl_object_finalize(Eo *obj, Efl_Container_Model_Data *sd EINA_UNUSED) { if (!efl_ui_view_model_get(obj)) { // Add a dummy object as source if there isn't any to allow using this class without source. efl_ui_view_model_set(obj, efl_add(EFL_GENERIC_MODEL_CLASS, obj)); } return efl_finalize(efl_super(obj, EFL_CONTAINER_MODEL_CLASS)); } static void _efl_container_model_efl_object_destructor(Eo *obj, Efl_Container_Model_Data *sd) { eina_hash_free(sd->properties); efl_destructor(efl_super(obj, EFL_CONTAINER_MODEL_CLASS)); } static const Eina_Value_Type * _efl_container_model_child_property_value_type_get(Eo *obj EINA_UNUSED, Efl_Container_Model_Data *sd, const char *property) { Efl_Container_Property_Data *cpd; Eina_Stringshare *key; key = eina_stringshare_add(property); cpd = eina_hash_find(sd->properties, key); eina_stringshare_del(key); if (!cpd) return NULL; return cpd->type; } static Eina_Bool _efl_container_model_child_property_add(Eo *obj, Efl_Container_Model_Data *sd, const char *name, const Eina_Value_Type *type, Eina_Iterator *values) { Eina_Array *arr = NULL; void *original; Efl_Container_Property_Data *cpd = NULL; unsigned int i; Eina_Error err = EFL_MODEL_ERROR_INCORRECT_VALUE; name = eina_stringshare_add(name); if (!type || !values) { EINA_LOG_WARN("Invalid input data"); goto on_error; } err = ENOMEM; arr = eina_array_new(4); if (!arr) goto on_error; EINA_ITERATOR_FOREACH(values, original) { Eina_Value *copy = eina_value_new(type); Eina_Bool r; if (type == EINA_VALUE_TYPE_STRINGSHARE || type == EINA_VALUE_TYPE_STRING) r = eina_value_set(copy, original); else r = eina_value_pset(copy, original); if (!r) { eina_value_free(copy); copy = eina_value_error_new(EINA_ERROR_VALUE_FAILED); } eina_array_push(arr, copy); } eina_iterator_free(values); err = EFL_MODEL_ERROR_UNKNOWN; cpd = eina_hash_find(sd->properties, name); if (!cpd) { cpd = calloc(1, sizeof(Efl_Container_Property_Data)); if (!cpd) goto on_error; cpd->name = eina_stringshare_ref(name); cpd->type = type; cpd->values = arr; if (!eina_hash_direct_add(sd->properties, name, cpd)) goto on_error; } else { _property_values_free(cpd->values); cpd->type = type; cpd->values = arr; } for (i = sd->children_count; i < eina_array_count(arr); ++i) { Efl_Model_Children_Event cevt = { 0 }; cevt.index = i; efl_event_callback_call(obj, EFL_MODEL_EVENT_CHILD_ADDED, &cevt); } if (eina_array_count(arr) > sd->children_count) { sd->children_count = eina_array_count(arr); efl_event_callback_call(obj, EFL_MODEL_EVENT_CHILDREN_COUNT_CHANGED, NULL); } eina_stringshare_del(name); return EINA_TRUE; on_error: eina_stringshare_del(name); if (cpd) free(cpd); if (arr) _property_values_free(arr); eina_error_set(err); return EINA_FALSE; } static Eina_Iterator * _efl_container_model_efl_model_properties_get(const Eo *obj EINA_UNUSED, Efl_Container_Model_Data *sd) { EFL_COMPOSITE_MODEL_PROPERTIES_SUPER(props, obj, EFL_CONTAINER_MODEL_CLASS, eina_hash_iterator_key_new(sd->parent->properties)); return props; } static Eina_Future * _efl_container_model_efl_model_property_set(Eo *obj, Efl_Container_Model_Data *pd, const char *property, Eina_Value *value) { if (pd->parent) { Efl_Container_Property_Data *cpd; Eina_Stringshare *name; unsigned int index; Eina_Value r = EINA_VALUE_EMPTY; name = eina_stringshare_add(property); cpd = eina_hash_find(pd->parent->properties, name); eina_stringshare_del(name); // Check if this is a property of this object if (!cpd) goto not_mine; // Check if we can get the expected type for this property if (!cpd->values) return efl_loop_future_rejected(obj, EFL_MODEL_ERROR_INCORRECT_VALUE); index = efl_composite_model_index_get(obj); // Try converting the type before touching any data inside the Model if (eina_value_type_get(value) != cpd->type) { eina_value_setup(&r, cpd->type); if (!eina_value_convert(value, &r)) return efl_loop_future_rejected(obj, EFL_MODEL_ERROR_INCORRECT_VALUE); } else { eina_value_copy(&r, value); } // Expand the array to have enough space for this value if it wasn't already the case while (index >= eina_array_count(cpd->values)) eina_array_push(cpd->values, eina_value_error_new(EFL_MODEL_ERROR_INCORRECT_VALUE)); // Clean the previous value and introduce the new one eina_value_free(eina_array_data_get(cpd->values, index)); // Same type as the expected type, we can just replace the value eina_array_data_set(cpd->values, index, eina_value_dup(&r)); eina_value_free(value); return efl_loop_future_resolved(obj, r); } not_mine: return efl_model_property_set(efl_super(obj, EFL_CONTAINER_MODEL_CLASS), property, value); } static Eina_Value * _efl_container_model_efl_model_property_get(const Eo *obj, Efl_Container_Model_Data *pd, const char *property) { if (pd->parent) { Efl_Container_Property_Data *cpd; Eina_Stringshare *name; Eina_Value *copy; unsigned int index; name = eina_stringshare_add(property); cpd = eina_hash_find(pd->parent->properties, name); eina_stringshare_del(name); // Check if this is a property of this object if (!cpd) goto not_mine; // Check if we can get the expected type for this property if (!cpd->values) return eina_value_error_new(EFL_MODEL_ERROR_INCORRECT_VALUE); index = efl_composite_model_index_get(obj); if (index >= eina_array_count(cpd->values)) return eina_value_error_new(EFL_MODEL_ERROR_INCORRECT_VALUE); copy = eina_value_dup(eina_array_data_get(cpd->values, index)); return copy; } not_mine: return efl_model_property_get(efl_super(obj, EFL_CONTAINER_MODEL_CLASS), property); } static unsigned int _efl_container_model_efl_model_children_count_get(const Eo *obj EINA_UNUSED, Efl_Container_Model_Data *sd) { unsigned int pcount; pcount = efl_model_children_count_get(efl_super(obj, EFL_CONTAINER_MODEL_CLASS)); return pcount > sd->children_count ? pcount : sd->children_count; } #include "efl_container_model.eo.c"