diff --git a/legacy/eina/src/include/eina_model.h b/legacy/eina/src/include/eina_model.h index c634d179a2..5390ba30c2 100644 --- a/legacy/eina/src/include/eina_model.h +++ b/legacy/eina/src/include/eina_model.h @@ -534,6 +534,14 @@ EAPI void eina_model_xunref(Eina_Model *model, * @li child,inserted: new child was added (eina_model_child_append() or eina_model_child_insert_at()) * @li child,set: child was replaced (eina_model_child_set()) * @li child,deleted: eina_model_child_del() was done. + * @li loaded: eina_model_load() was done. + * @li unloaded: eina_model_unload() was done. + * + * Mix-in interfaces may emit these: + * @li properties,loaded + * @li properties,unloaded + * @li children,loaded + * @li children,unloaded * * One can be notified of events with eina_model_event_callback_add(). * diff --git a/legacy/eina/src/lib/eina_model.c b/legacy/eina/src/lib/eina_model.c index 70d5fad027..8af7a07143 100644 --- a/legacy/eina/src/lib/eina_model.c +++ b/legacy/eina/src/lib/eina_model.c @@ -86,6 +86,12 @@ static const char _eina_model_str_children_changed[] = "children,changed"; static const char _eina_model_str_child_inserted[] = "child,inserted"; static const char _eina_model_str_child_set[] = "child,set"; static const char _eina_model_str_child_del[] = "child,deleted"; +static const char _eina_model_str_loaded[] = "loaded"; +static const char _eina_model_str_unloaded[] = "unloaded"; +static const char _eina_model_str_properties_loaded[] = "properties,loaded"; +static const char _eina_model_str_properties_unloaded[] = "properties,unloaded"; +static const char _eina_model_str_children_loaded[] = "children,loaded"; +static const char _eina_model_str_children_unloaded[] = "children,unloaded"; #ifdef CRITICAL #undef CRITICAL @@ -1992,6 +1998,8 @@ static const Eina_Model_Event_Description _eina_model_type_base_events[] = { EINA_MODEL_EVENT_DESCRIPTION(_eina_model_str_child_inserted, "u", "model child was inserted, child position is given."), EINA_MODEL_EVENT_DESCRIPTION(_eina_model_str_child_set, "u", "model child was set, child position is given."), EINA_MODEL_EVENT_DESCRIPTION(_eina_model_str_child_del, "u", "model child was deleted, child position is given."), + EINA_MODEL_EVENT_DESCRIPTION(_eina_model_str_loaded, "", "model was loaded"), + EINA_MODEL_EVENT_DESCRIPTION(_eina_model_str_unloaded, "", "model was unloaded"), EINA_MODEL_EVENT_DESCRIPTION_SENTINEL }; @@ -2375,6 +2383,12 @@ static const Eina_Model_Type _EINA_MODEL_TYPE_MIXIN = { }; #undef EINA_MODEL_TYPE_MIXIN_GET +/* Events for all Properties interface */ +static const Eina_Model_Event_Description _eina_model_interface_properties_events[] = { + EINA_MODEL_EVENT_DESCRIPTION(_eina_model_str_properties_loaded, "", "model properties were loaded"), + EINA_MODEL_EVENT_DESCRIPTION(_eina_model_str_properties_unloaded, "", "model properties were unloaded"), + EINA_MODEL_EVENT_DESCRIPTION_SENTINEL +}; /* EINA_MODEL_INTERFACE_PROPERTIES_HASH ******************************/ @@ -2536,7 +2550,7 @@ static const Eina_Model_Interface_Properties _EINA_MODEL_INTERFACE_PROPERTIES_HA sizeof(Eina_Model_Interface_Properties), _EINA_MODEL_INTERFACE_NAME_PROPERTIES, NULL, /* no parent interfaces */ - NULL, /* no extra events */ + _eina_model_interface_properties_events, _eina_model_interface_properties_hash_setup, _eina_model_interface_properties_hash_flush, _eina_model_interface_properties_hash_constructor, @@ -2686,7 +2700,7 @@ static const Eina_Model_Interface_Properties _EINA_MODEL_INTERFACE_PROPERTIES_ST sizeof(Eina_Model_Interface_Properties), _EINA_MODEL_INTERFACE_NAME_PROPERTIES, NULL, /* no parent interfaces */ - NULL, /* no extra events */ + _eina_model_interface_properties_events, _eina_model_interface_properties_struct_setup, _eina_model_interface_properties_struct_flush, _eina_model_interface_properties_struct_constructor, @@ -2708,6 +2722,13 @@ static const Eina_Model_Interface_Properties _EINA_MODEL_INTERFACE_PROPERTIES_ST _eina_model_interface_properties_struct_names_list }; +/* Events for all Children interface */ +static const Eina_Model_Event_Description _eina_model_interface_children_events[] = { + EINA_MODEL_EVENT_DESCRIPTION(_eina_model_str_children_loaded, "", "model children were loaded"), + EINA_MODEL_EVENT_DESCRIPTION(_eina_model_str_children_unloaded, "", "model children were unloaded"), + EINA_MODEL_EVENT_DESCRIPTION_SENTINEL +}; + /* EINA_MODEL_INTERFACE_CHILDREN_INARRAY ******************************/ #define EINA_MODEL_INTERFACE_CHILDREN_INARRAY_GET(model) \ @@ -2864,7 +2885,7 @@ static const Eina_Model_Interface_Children _EINA_MODEL_INTERFACE_CHILDREN_INARRA sizeof(Eina_Model_Interface_Children), _EINA_MODEL_INTERFACE_NAME_CHILDREN, NULL, /* no parent interfaces */ - NULL, /* no extra events */ + _eina_model_interface_children_events, _eina_model_interface_children_inarray_setup, _eina_model_interface_children_inarray_flush, _eina_model_interface_children_inarray_constructor, @@ -3988,15 +4009,52 @@ eina_model_compare(const Eina_Model *a, const Eina_Model *b) EAPI Eina_Bool eina_model_load(Eina_Model *model) { + Eina_Bool ret; + EINA_MODEL_INSTANCE_CHECK_VAL(model, EINA_FALSE); - EINA_MODEL_TYPE_CALL_OPTIONAL_RETURN(model, load, EINA_TRUE); + + eina_error_set(0); + if (model->desc->ops.type.load) + { + ret = model->desc->ops.type.load(model); + if (ret) + _eina_model_event_callback_call(model, _eina_model_str_loaded, NULL); + } + else + { + eina_error_set(EINA_ERROR_MODEL_METHOD_MISSING); + ret = EINA_FALSE; + ERR("Method load() not implemented for model %p (%s)", + model, model->desc->cache.types[0]->name); + } + + return ret; } EAPI Eina_Bool eina_model_unload(Eina_Model *model) { + Eina_Bool ret; + EINA_MODEL_INSTANCE_CHECK_VAL(model, EINA_FALSE); - EINA_MODEL_TYPE_CALL_OPTIONAL_RETURN(model, unload, EINA_TRUE); + + eina_error_set(0); + if (model->desc->ops.type.unload) + { + ret = model->desc->ops.type.unload(model); + if (ret) + _eina_model_event_callback_call + (model, _eina_model_str_unloaded, NULL); + } + else + { + eina_error_set(EINA_ERROR_MODEL_METHOD_MISSING); + ret = EINA_FALSE; + ERR("Method unload() not implemented for model %p (%s)", + model, model->desc->cache.types[0]->name); + } + + return ret; } EAPI Eina_Bool @@ -5062,26 +5120,40 @@ EAPI Eina_Bool eina_model_interface_properties_load(const Eina_Model_Interface *iface, Eina_Model *model) { Eina_Bool (*load)(Eina_Model *); + Eina_Bool ret; EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL(iface, model, EINA_FALSE); load = _eina_model_interface_find_offset (iface, offsetof(Eina_Model_Interface_Properties, load)); EINA_SAFETY_ON_NULL_RETURN_VAL(load, EINA_FALSE); - return load(model); + ret = load(model); + + if (ret) + _eina_model_event_callback_call + (model, _eina_model_str_properties_loaded, NULL); + + return ret; } EAPI Eina_Bool eina_model_interface_properties_unload(const Eina_Model_Interface *iface, Eina_Model *model) { Eina_Bool (*unload)(Eina_Model *); + Eina_Bool ret; EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL(iface, model, EINA_FALSE); unload = _eina_model_interface_find_offset (iface, offsetof(Eina_Model_Interface_Properties, unload)); EINA_SAFETY_ON_NULL_RETURN_VAL(unload, EINA_FALSE); - return unload(model); + ret = unload(model); + + if (ret) + _eina_model_event_callback_call + (model, _eina_model_str_properties_unloaded, NULL); + + return ret; } EAPI Eina_Bool @@ -5166,26 +5238,40 @@ EAPI Eina_Bool eina_model_interface_children_load(const Eina_Model_Interface *iface, Eina_Model *model) { Eina_Bool (*load)(Eina_Model *); + Eina_Bool ret; EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL(iface, model, EINA_FALSE); load = _eina_model_interface_find_offset (iface, offsetof(Eina_Model_Interface_Children, load)); EINA_SAFETY_ON_NULL_RETURN_VAL(load, EINA_FALSE); - return load(model); + ret = load(model); + + if (ret) + _eina_model_event_callback_call + (model, _eina_model_str_children_loaded, NULL); + + return ret; } EAPI Eina_Bool eina_model_interface_children_unload(const Eina_Model_Interface *iface, Eina_Model *model) { Eina_Bool (*unload)(Eina_Model *); + Eina_Bool ret; EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL(iface, model, EINA_FALSE); unload = _eina_model_interface_find_offset (iface, offsetof(Eina_Model_Interface_Children, unload)); EINA_SAFETY_ON_NULL_RETURN_VAL(unload, EINA_FALSE); - return unload(model); + ret = unload(model); + + if (ret) + _eina_model_event_callback_call + (model, _eina_model_str_children_unloaded, NULL); + + return ret; } EAPI int diff --git a/legacy/eina/src/tests/eina_test_model.c b/legacy/eina/src/tests/eina_test_model.c index 97a69dbec4..54a22581b0 100644 --- a/legacy/eina/src/tests/eina_test_model.c +++ b/legacy/eina/src/tests/eina_test_model.c @@ -1112,6 +1112,164 @@ START_TEST(eina_model_test_inheritance) } END_TEST +static Eina_Bool +_myproperties_load(Eina_Model *m) +{ + Eina_Value v; + Eina_Bool ret; + int count; + + if (!eina_model_property_get(m, "load_count", &v)) + return EINA_FALSE; + + eina_value_get(&v, &count); + count++; + eina_value_set(&v, count); + + ret = eina_model_property_set(m, "load_count", &v); + eina_value_flush(&v); + + return ret; +} + +static Eina_Bool +_myproperties_unload(Eina_Model *m) +{ + Eina_Value v; + Eina_Bool ret; + int count; + + if (!eina_model_property_get(m, "load_count", &v)) + return EINA_FALSE; + + eina_value_get(&v, &count); + count--; + eina_value_set(&v, count); + + ret = eina_model_property_set(m, "load_count", &v); + eina_value_flush(&v); + + return ret; +} + +static Eina_Bool +_mychildren_load(Eina_Model *m) +{ + Eina_Model *c = eina_model_new(EINA_MODEL_TYPE_GENERIC); + int ret = eina_model_child_append(m, c); + eina_model_unref(c); + return ret >= 0; +} + +static Eina_Bool +_mychildren_unload(Eina_Model *m) +{ + int count = eina_model_child_count(m); + EINA_SAFETY_ON_FALSE_RETURN_VAL(count > 0, EINA_FALSE); + return eina_model_child_del(m, count - 1); +} + +START_TEST(eina_model_test_ifaces_load_unload) +{ + unsigned int count_loaded = 0, count_unloaded = 0; + unsigned int count_ploaded = 0, count_punloaded = 0; + unsigned int count_cloaded = 0, count_cunloaded = 0; + static Eina_Model_Interface_Properties piface; + static Eina_Model_Interface_Children ciface; + static const Eina_Model_Interface *piface_parents[2] = {NULL, NULL}; + static const Eina_Model_Interface *ciface_parents[2] = {NULL, NULL}; + static const Eina_Model_Interface *type_ifaces[3] = { + &piface.base, &ciface.base, NULL + }; + static Eina_Model_Type type; + Eina_Model *m; + Eina_Value v; + int count; + + eina_init(); + + /* do after eina_init() otherwise interfaces are not set */ + piface_parents[0] = EINA_MODEL_INTERFACE_PROPERTIES_HASH; + ciface_parents[0] = EINA_MODEL_INTERFACE_CHILDREN_INARRAY; + + memset(&piface, 0, sizeof(piface)); + piface.base.version = EINA_MODEL_INTERFACE_VERSION; + piface.base.interface_size = sizeof(piface); + piface.base.name = EINA_MODEL_INTERFACE_NAME_PROPERTIES; + piface.base.interfaces = piface_parents; + piface.load = _myproperties_load; + piface.unload = _myproperties_unload; + + memset(&ciface, 0, sizeof(ciface)); + ciface.base.version = EINA_MODEL_INTERFACE_VERSION; + ciface.base.interface_size = sizeof(ciface); + ciface.base.name = EINA_MODEL_INTERFACE_NAME_CHILDREN; + ciface.base.interfaces = ciface_parents; + ciface.load = _mychildren_load; + ciface.unload = _mychildren_unload; + + type.version = EINA_MODEL_TYPE_VERSION; + type.private_size = 0; + type.name = "MyType"; + eina_model_type_subclass_setup(&type, EINA_MODEL_TYPE_GENERIC); + type.interfaces = type_ifaces; + + m = eina_model_new(&type); + fail_unless(m != NULL); + + eina_model_event_callback_add + (m, "loaded", _eina_test_model_cb_count, &count_loaded); + eina_model_event_callback_add + (m, "unloaded", _eina_test_model_cb_count, &count_unloaded); + + eina_model_event_callback_add + (m, "properties,loaded", _eina_test_model_cb_count, &count_ploaded); + eina_model_event_callback_add + (m, "properties,unloaded", _eina_test_model_cb_count, &count_punloaded); + + eina_model_event_callback_add + (m, "children,loaded", _eina_test_model_cb_count, &count_cloaded); + eina_model_event_callback_add + (m, "children,unloaded", _eina_test_model_cb_count, &count_cunloaded); + + fail_unless(eina_value_setup(&v, EINA_VALUE_TYPE_INT)); + fail_unless(eina_value_set(&v, 0)); + fail_unless(eina_model_property_set(m, "load_count", &v)); + eina_value_flush(&v); + + fail_unless(eina_model_load(m)); + fail_unless(eina_model_load(m)); + fail_unless(eina_model_load(m)); + + /* each load increments one for load_count property */ + fail_unless(eina_model_property_get(m, "load_count", &v)); + fail_unless(eina_value_pget(&v, &count)); + ck_assert_int_eq(count, 3); + eina_value_flush(&v); + + /* each load adds one child */ + ck_assert_int_eq(eina_model_child_count(m), 3); + + fail_unless(eina_model_unload(m)); + fail_unless(eina_model_unload(m)); + fail_unless(eina_model_unload(m)); + + ck_assert_int_eq(count_loaded, 3); + ck_assert_int_eq(count_unloaded, 3); + + ck_assert_int_eq(count_ploaded, 3); + ck_assert_int_eq(count_punloaded, 3); + + ck_assert_int_eq(count_cloaded, 3); + ck_assert_int_eq(count_cunloaded, 3); + + ck_assert_int_eq(eina_model_refcount(m), 1); + eina_model_unref(m); + + eina_shutdown(); +} +END_TEST + void eina_test_model(TCase *tc) { @@ -1126,4 +1284,5 @@ eina_test_model(TCase *tc) tcase_add_test(tc, eina_model_test_struct); tcase_add_test(tc, eina_model_test_struct_complex_members); tcase_add_test(tc, eina_model_test_inheritance); + tcase_add_test(tc, eina_model_test_ifaces_load_unload); }