ecore: correctly handle children removal in Efl.Composite_Model by updating all required index.

Reviewed-by: Marcel Hollerbach <mail@marcel-hollerbach.de>
Differential Revision: https://phab.enlightenment.org/D10032
This commit is contained in:
Cedric Bail 2019-09-18 19:31:05 -07:00 committed by Marcel Hollerbach
parent 06d328ffd1
commit 6e49752712
1 changed files with 85 additions and 20 deletions

View File

@ -40,7 +40,26 @@ 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;
if (node->index > (unsigned int) *key) return 1;
if (node->index < (unsigned int) *key) return -1;
return 0;
}
static void
_mark_greater(Efl_Composite_Model_Data *root, Eina_Array *mark, const unsigned int upper)
{
if (!root) return ;
if (root->index > upper)
{
eina_array_push(mark, root);
_mark_greater((void*) EINA_RBTREE_GET(root)->son[0], mark, upper);
_mark_greater((void*) EINA_RBTREE_GET(root)->son[1], mark, upper);
}
else
{
_mark_greater((void*) EINA_RBTREE_GET(root)->son[0], mark, upper);
}
}
static void
@ -136,20 +155,75 @@ _efl_composite_model_index_get(const Eo *obj, Efl_Composite_Model_Data *pd)
return r;
}
static void
_efl_composite_model_child_event(Efl_Composite_Model_Data *pd,
const Efl_Model_Children_Event *ev,
const Efl_Event_Description *description)
{
Efl_Composite_Model_Data *cpd;
Efl_Model_Children_Event cev = { 0 };
Eina_Array mark;
Eina_Array_Iterator iterator;
unsigned int i;
cev.index = ev->index;
if (ev->child)
{
cev.child = _efl_composite_lookup(efl_class_get(pd->self),
pd->self, ev->child, ev->index);
}
else
{
cpd = (void*) eina_rbtree_inline_lookup(pd->indexed, &cev.index, sizeof (unsigned int),
EINA_RBTREE_CMP_KEY_CB(_children_indexed_key), NULL);
if (cpd) cev.child = efl_ref(cpd->self);
}
if (cev.child && description == EFL_MODEL_EVENT_CHILD_REMOVED)
{
cpd = efl_data_scope_get(cev.child, EFL_COMPOSITE_MODEL_CLASS);
// Remove child from lookup tree if it exist before triggering anything further
pd->indexed = eina_rbtree_inline_remove(pd->indexed, EINA_RBTREE_GET(cpd),
EINA_RBTREE_CMP_NODE_CB(_children_indexed_cmp), NULL);
cpd->inserted = EINA_FALSE;
efl_replace(&cpd->source, NULL);
}
// Update all index above this one if necessaryy
eina_array_step_set(&mark, sizeof (Eina_Array), 8);
_mark_greater((void*) pd->indexed, &mark, cev.index);
// Correct index of the object stored that need to
// There is no need to remove and reinsert them as their relative order will not change.
EINA_ARRAY_ITER_NEXT(&mark, i, cpd, iterator)
{
if (description == EFL_MODEL_EVENT_CHILD_REMOVED) cpd->index--;
else cpd->index++;
efl_ref(cpd->self);
}
efl_event_callback_call(pd->self, description, &cev);
// Notify of the index change only after notifying of the removal top avoid overlap
EINA_ARRAY_ITER_NEXT(&mark, i, cpd, iterator)
{
efl_model_properties_changed(cpd->self, EFL_COMPOSITE_MODEL_CHILD_INDEX);
efl_unref(cpd->self);
}
eina_array_flush(&mark);
efl_unref(cev.child);
}
static void
_efl_composite_model_child_added(void *data, const Efl_Event *event)
{
Efl_Composite_Model_Data *pd = data;
Efl_Model_Children_Event *ev = event->info;
Efl_Model_Children_Event cev = { 0 };
cev.index = ev->index;
if (ev->child)
cev.child = _efl_composite_lookup(efl_class_get(pd->self),
pd->self, ev->child, ev->index);
efl_event_callback_call(pd->self, EFL_MODEL_EVENT_CHILD_ADDED, &cev);
efl_unref(cev.child);
_efl_composite_model_child_event(pd, ev, EFL_MODEL_EVENT_CHILD_ADDED);
}
static void
@ -157,16 +231,8 @@ _efl_composite_model_child_removed(void *data, const Efl_Event *event)
{
Efl_Composite_Model_Data *pd = data;
Efl_Model_Children_Event *ev = event->info;
Efl_Model_Children_Event cev = { 0 };
cev.index = ev->index;
if (ev->child)
cev.child = _efl_composite_lookup(efl_class_get(pd->self),
pd->self, ev->child, ev->index);
efl_event_callback_call(pd->self, EFL_MODEL_EVENT_CHILD_REMOVED, &cev);
efl_unref(cev.child);
_efl_composite_model_child_event(pd, ev, EFL_MODEL_EVENT_CHILD_REMOVED);
}
EFL_CALLBACKS_ARRAY_DEFINE(composite_callbacks,
@ -427,8 +493,7 @@ _efl_composite_model_efl_object_destructor(Eo *obj, Efl_Composite_Model_Data *pd
efl_event_callback_forwarder_del(pd->source, EFL_MODEL_EVENT_CHILDREN_COUNT_CHANGED, obj);
efl_event_callback_forwarder_del(pd->source, EFL_MODEL_EVENT_PROPERTIES_CHANGED, obj);
efl_unref(pd->source);
pd->source = NULL;
efl_replace(&pd->source, NULL);
}
efl_destructor(efl_super(obj, EFL_COMPOSITE_MODEL_CLASS));