forked from enlightenment/efl
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:
parent
4b1622b5fc
commit
7bd3942e23
|
@ -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,
|
||||
|
|
|
@ -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; }
|
||||
|
|
Loading…
Reference in New Issue