summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCedric Bail <cedric.bail@free.fr>2019-09-18 19:31:05 -0700
committerMarcel Hollerbach <mail@marcel-hollerbach.de>2019-09-24 09:18:42 +0200
commit6e497527125e4727e6168b1ee4b54d4146808633 (patch)
tree0279fb1bfe013334c662c236dc70b36eb8cc7b85
parent06d328ffd114c791491fbe3fbc22bcbffd02560c (diff)
downloadefl-6e497527125e4727e6168b1ee4b54d4146808633.tar.gz
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
-rw-r--r--src/lib/ecore/efl_composite_model.c99
1 files changed, 82 insertions, 17 deletions
diff --git a/src/lib/ecore/efl_composite_model.c b/src/lib/ecore/efl_composite_model.c
index 26322357d2..b3896bc99e 100644
--- a/src/lib/ecore/efl_composite_model.c
+++ b/src/lib/ecore/efl_composite_model.c
@@ -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
@@ -137,36 +156,83 @@ _efl_composite_model_index_get(const Eo *obj, Efl_Composite_Model_Data *pd)
}
static void
-_efl_composite_model_child_added(void *data, const Efl_Event *event)
+_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 *pd = data;
- Efl_Model_Children_Event *ev = event->info;
+ 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);
- efl_event_callback_call(pd->self, EFL_MODEL_EVENT_CHILD_ADDED, &cev);
+ {
+ 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_removed(void *data, const Efl_Event *event)
+_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_composite_model_child_event(pd, ev, EFL_MODEL_EVENT_CHILD_ADDED);
+}
- efl_event_callback_call(pd->self, EFL_MODEL_EVENT_CHILD_REMOVED, &cev);
+static void
+_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_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));