ecore: prevent duplication of children for Efl.Composite_Model and enable dummy object.

This patch allow Efl.Composite_Model to return always the same object for the same index.
This way, it make it easier for the Model to always be in sync even if there is multiple
user at any time. The support for dummy object allow the Composite_Model to host more
object than what the source model provide. This dummy model will only have the property
of the Composite_Model and none of the Source model ofcourse.

Reviewed-by: Vitor Sousa da Silva <vitorsousa@expertisesolutions.com.br>
Differential Revision: https://phab.enlightenment.org/D8045
This commit is contained in:
Cedric BAIL 2019-02-27 18:17:30 -08:00
parent 4b1622b5fc
commit 7bd3942e23
2 changed files with 140 additions and 1 deletions

View File

@ -16,14 +16,36 @@ typedef struct _Efl_Composite_Model_Data Efl_Composite_Model_Data;
struct _Efl_Composite_Model_Data
{
EINA_RBTREE;
Efl_Composite_Model *self;
Efl_Model *source;
Eina_Rbtree *indexed;
unsigned int index;
Eina_Bool need_index : 1;
Eina_Bool set_index : 1;
Eina_Bool inserted : 1;
};
static Eina_Rbtree_Direction
_children_indexed_cmp(const Efl_Composite_Model_Data *left,
const Efl_Composite_Model_Data *right,
void *data EINA_UNUSED)
{
if (left->index < right->index)
return EINA_RBTREE_LEFT;
return EINA_RBTREE_RIGHT;
}
static int
_children_indexed_key(const Efl_Composite_Model_Data *node,
const int *key, int length EINA_UNUSED, void *data EINA_UNUSED)
{
return node->index - *key;
}
static void
_efl_composite_model_efl_object_destructor(Eo *obj, Efl_Composite_Model_Data *pd)
{
@ -41,15 +63,68 @@ _efl_composite_model_efl_object_destructor(Eo *obj, Efl_Composite_Model_Data *pd
efl_destructor(efl_super(obj, EFL_COMPOSITE_MODEL_CLASS));
}
static void
_efl_composite_model_efl_object_invalidate(Eo *obj, Efl_Composite_Model_Data *pd)
{
if (pd->inserted)
{
Eo *parent;
parent = efl_parent_get(obj);
if (efl_isa(parent, EFL_COMPOSITE_MODEL_CLASS))
{
Efl_Composite_Model_Data *ppd;
ppd = efl_data_scope_get(parent, EFL_COMPOSITE_MODEL_CLASS);
ppd->indexed = eina_rbtree_inline_remove(ppd->indexed, EINA_RBTREE_GET(pd),
EINA_RBTREE_CMP_NODE_CB(_children_indexed_cmp), NULL);
pd->inserted = EINA_FALSE;
}
else
{
ERR("Unexpected parent change during the life of object: %s this might lead to crash.", efl_debug_name_get(obj));
}
}
efl_invalidate(efl_super(obj, EFL_COMPOSITE_MODEL_CLASS));
}
static Efl_Object *
_efl_composite_model_efl_object_finalize(Eo *obj, Efl_Composite_Model_Data *pd)
{
Eo *parent;
if (pd->source == NULL)
{
ERR("Source of the composite model wasn't defined at construction time.");
return NULL;
}
pd->self = obj;
parent = efl_parent_get(obj);
if (efl_isa(parent, EFL_COMPOSITE_MODEL_CLASS) && !pd->inserted)
{
Efl_Composite_Model_Data *ppd = efl_data_scope_get(parent, EFL_COMPOSITE_MODEL_CLASS);
Efl_Composite_Model_Data *lookup;
lookup = (void*) eina_rbtree_inline_lookup(ppd->indexed, &pd->index, sizeof (int),
EINA_RBTREE_CMP_KEY_CB(_children_indexed_key), NULL);
if (lookup)
{
// There is already an object at this index, we should not
// build anything different than what exist. Returning existing one.
return lookup->self;
}
else
{
ppd->indexed = eina_rbtree_inline_insert(ppd->indexed, EINA_RBTREE_GET(pd),
EINA_RBTREE_CMP_NODE_CB(_children_indexed_cmp), NULL);
pd->inserted = EINA_TRUE;
}
}
return obj;
}
@ -175,6 +250,7 @@ struct _Efl_Composite_Model_Slice_Request
const Efl_Class *self;
Eo *parent;
unsigned int start;
unsigned int dummy_need;
};
static Eina_Value
@ -203,6 +279,25 @@ _efl_composite_model_then(Eo *o EINA_UNUSED, void *data, const Eina_Value v)
efl_unref(composite);
}
while (req->dummy_need)
{
Eo *dummy, *dummy_proxy;
// Create a dummy object and its proxy
dummy = efl_add(EFL_GENERIC_MODEL_CLASS, req->parent);
dummy_proxy = efl_add_ref(req->self, req->parent,
efl_ui_view_model_set(efl_added, dummy),
efl_composite_model_index_set(efl_added, req->start + i),
efl_loop_model_volatile_make(efl_added));
efl_parent_set(dummy, dummy_proxy);
eina_value_array_append(&r, dummy_proxy);
efl_unref(dummy_proxy);
req->dummy_need--;
i++;
}
return r;
}
@ -223,8 +318,47 @@ _efl_composite_model_efl_model_children_slice_get(Eo *obj,
{
Efl_Composite_Model_Slice_Request *req;
Eina_Future *f;
unsigned int source_count, self_count;
unsigned int req_count;
f = efl_model_children_slice_get(pd->source, start, count);
source_count = efl_model_children_count_get(pd->source);
self_count = efl_model_children_count_get(obj);
if (start + count > source_count &&
start + count > self_count)
return efl_loop_future_rejected(obj, EFL_MODEL_ERROR_INCORRECT_VALUE);
if (start > source_count)
{
Eina_Value r = EINA_VALUE_EMPTY;
unsigned int i = 0;
eina_value_array_setup(&r, EINA_VALUE_TYPE_OBJECT, 4);
while (count)
{
Eo *dummy, *dummy_proxy;
// Create a dummy object and its proxy
dummy = efl_add(EFL_GENERIC_MODEL_CLASS, obj);
dummy_proxy = efl_add_ref(efl_class_get(obj), obj,
efl_ui_view_model_set(efl_added, dummy),
efl_composite_model_index_set(efl_added, start + i),
efl_loop_model_volatile_make(efl_added));
efl_parent_set(dummy, dummy_proxy);
eina_value_array_append(&r, dummy_proxy);
efl_unref(dummy_proxy);
count--;
i++;
}
return efl_loop_future_resolved(obj, r);
}
req_count = start + count > source_count ? source_count - start : count;
f = efl_model_children_slice_get(pd->source, start, req_count);
if (!f) return NULL;
req = malloc(sizeof (Efl_Composite_Model_Slice_Request));
@ -233,6 +367,10 @@ _efl_composite_model_efl_model_children_slice_get(Eo *obj,
req->self = efl_class_get(obj);
req->parent = efl_ref(obj);
req->start = start;
if (start + count < source_count)
req->dummy_need = 0;
else
req->dummy_need = count - (source_count - start);
return efl_future_then(obj, f, .success_type = EINA_VALUE_TYPE_ARRAY,
.success = _efl_composite_model_then,

View File

@ -21,6 +21,7 @@ class @beta Efl.Composite_Model extends Efl.Loop_Model implements Efl.Ui.View
}
implements {
Efl.Object.destructor;
Efl.Object.invalidate;
Efl.Object.finalize;
Efl.Ui.View.model { set; get; }
Efl.Model.property { set; get; }