efl/src/lib/ecore/efl_container_model.c

313 lines
8.7 KiB
C

#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <Efl.h>
#include <Eina.h>
#include <Eo.h>
#include <Ecore.h>
#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"