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)
{
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;
}
const Efl_Class *self;
Eo *parent;
unsigned int start;
+ unsigned int dummy_need;
};
static Eina_Value
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;
}
{
Efl_Composite_Model_Slice_Request *req;
Eina_Future *f;
+ unsigned int source_count, self_count;
+ unsigned int req_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);
+ }
- f = efl_model_children_slice_get(pd->source, start, count);
+ 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));
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,