aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLarry Jr <larry.olj@gmail.com>2017-01-31 18:17:58 -0200
committerCedric BAIL <cedric@osg.samsung.com>2017-02-06 15:26:21 -0800
commit093c5921888dd4810233c6ba3e97479758e2589c (patch)
treecea9d80b886a1e48f994f987535c209edcb704d9
parentecore: handle initialization of timer correctly. (diff)
downloadefl-093c5921888dd4810233c6ba3e97479758e2589c.tar.gz
efl: add efl_model and efl_ui_view classes
Efl.Model.Container and Efl.Model.Item to efl/interfaces are used to create Efl.Model objects with predefined property values. This is useful to any situation where we want an Efl.Model with explicit defined property values. Efl.Ui.View and Efl.Ui.Factory are used to connect Efl.Models with Widgets, Elm.Layout and Efl.Ui.Image has changed to use news interfaces Signed-off-by: Cedric BAIL <cedric@osg.samsung.com>
-rw-r--r--src/Makefile_Ecore.am7
-rw-r--r--src/Makefile_Efl.am34
-rw-r--r--src/Makefile_Elementary.am2
-rw-r--r--src/examples/elementary/Makefile.am2
-rw-r--r--src/examples/elementary/layout_model_connect.c176
-rw-r--r--src/lib/ecore/Ecore_Eo.h14
-rw-r--r--src/lib/ecore/efl_model_container.c298
-rw-r--r--src/lib/ecore/efl_model_container.eo60
-rw-r--r--src/lib/ecore/efl_model_container_item.c192
-rw-r--r--src/lib/ecore/efl_model_container_item.eo39
-rw-r--r--src/lib/ecore/efl_model_container_private.h32
-rw-r--r--src/lib/ecore/efl_model_item.c202
-rw-r--r--src/lib/ecore/efl_model_item.eo26
-rw-r--r--src/lib/efl/Efl.h5
-rw-r--r--src/lib/efl/Efl_Model_Common.h1
-rw-r--r--src/lib/efl/interfaces/efl_interfaces_main.c4
-rw-r--r--src/lib/efl/interfaces/efl_model_common.c6
-rw-r--r--src/lib/efl/interfaces/efl_ui_factory.eo19
-rw-r--r--src/lib/efl/interfaces/efl_ui_model_connect.eo11
-rw-r--r--src/lib/efl/interfaces/efl_ui_model_factory_connect.eo11
-rw-r--r--src/lib/efl/interfaces/efl_ui_view.eo12
-rw-r--r--src/lib/elementary/Elementary.h1
-rw-r--r--src/lib/elementary/efl_ui_image.c198
-rw-r--r--src/lib/elementary/efl_ui_image.eo5
-rw-r--r--src/lib/elementary/efl_ui_image_factory.c59
-rw-r--r--src/lib/elementary/efl_ui_image_factory.eo10
-rw-r--r--src/lib/elementary/efl_ui_widget_image.h5
-rw-r--r--src/lib/elementary/elm_layout.c320
-rw-r--r--src/lib/elementary/elm_layout.eo6
-rw-r--r--src/lib/elementary/elm_widget_layout.h4
-rw-r--r--src/lib/eo/eina_types.eot2
-rw-r--r--src/tests/efl/efl_suite.c51
-rw-r--r--src/tests/efl/efl_suite.h26
-rw-r--r--src/tests/efl/efl_test_model_container.c171
-rw-r--r--src/tests/elementary/elm_test_layout.c36
35 files changed, 2045 insertions, 2 deletions
diff --git a/src/Makefile_Ecore.am b/src/Makefile_Ecore.am
index 7ebef696ce..3cb58b6b43 100644
--- a/src/Makefile_Ecore.am
+++ b/src/Makefile_Ecore.am
@@ -26,6 +26,9 @@ ecore_eolian_files_public = \
ecore_eolian_files = \
$(ecore_eolian_files_public) \
lib/ecore/efl_promise.eo \
+ lib/ecore/efl_model_item.eo \
+ lib/ecore/efl_model_container.eo \
+ lib/ecore/efl_model_container_item.eo \
$(ecore_eolian_files_legacy)
ecore_eolian_type_files = \
@@ -86,6 +89,10 @@ lib/ecore/efl_io_file.c \
lib/ecore/efl_io_copier.c \
lib/ecore/efl_io_buffered_stream.c \
lib/ecore/efl_promise.c \
+lib/ecore/efl_model_item.c \
+lib/ecore/efl_model_container.c \
+lib/ecore/efl_model_container_item.c \
+lib/ecore/efl_model_container_private.h \
lib/ecore/ecore_pipe.c \
lib/ecore/ecore_poller.c \
lib/ecore/ecore_time.c \
diff --git a/src/Makefile_Efl.am b/src/Makefile_Efl.am
index 79f46611d0..faccdf5bac 100644
--- a/src/Makefile_Efl.am
+++ b/src/Makefile_Efl.am
@@ -43,6 +43,10 @@ efl_eolian_files = \
lib/efl/interfaces/efl_vpath_file_core.eo \
lib/efl/interfaces/efl_ui_spin.eo \
lib/efl/interfaces/efl_ui_progress.eo \
+ lib/efl/interfaces/efl_ui_view.eo \
+ lib/efl/interfaces/efl_ui_model_connect.eo \
+ lib/efl/interfaces/efl_ui_factory.eo \
+ lib/efl/interfaces/efl_ui_model_factory_connect.eo \
lib/efl/interfaces/efl_screen.eo \
lib/efl/interfaces/efl_io_closer.eo \
lib/efl/interfaces/efl_io_positioner.eo \
@@ -171,3 +175,33 @@ bin_efl_efl_debug_CPPFLAGS = -I$(top_builddir)/src/bin/efl @EINA_CFLAGS@ @ECORE_
bin_efl_efl_debug_LDADD = @EFL_LIBS@ @USE_EINA_INTERNAL_LIBS@ @USE_ECORE_INTERNAL_LIBS@ @USE_ECORE_CON_INTERNAL_LIBS@
bin_efl_efl_debug_DEPENDENCIES = @USE_EINA_INTERNAL_LIBS@ @USE_ECORE_INTERNAL_LIBS@ @USE_ECORE_CON_INTERNAL_LIBS@
+
+if EFL_ENABLE_TESTS
+
+check_PROGRAMS += tests/efl/efl_suite
+TESTS += tests/efl/efl_suite
+
+tests_efl_efl_suite_SOURCES = \
+tests/efl/efl_suite.c \
+tests/efl/efl_test_model_container.c \
+tests/efl/efl_suite.h
+
+tests_efl_efl_suite_CPPFLAGS = -I$(top_builddir)/src/lib/efl \
+-DTESTS_SRC_DIR=\"$(top_srcdir)/src/tests/efl\" \
+-DTESTS_BUILD_DIR=\"$(top_builddir)/src/tests/efl\" \
+@CHECK_CFLAGS@ \
+@ECORE_CFLAGS@ \
+@EFL_CFLAGS@
+
+
+tests_efl_efl_suite_LDADD = @CHECK_LIBS@ \
+@EFL_LIBS@ \
+@USE_EFL_LIBS@ \
+@USE_ECORE_LIBS@ -lecore
+
+tests_efl_efl_suite_DEPENDENCIES = \
+@USE_EFL_INTERNAL_LIBS@ \
+@USE_ECORE_INTERNAL_LIBS@
+
+endif
+
diff --git a/src/Makefile_Elementary.am b/src/Makefile_Elementary.am
index c3c685e11e..0f6973cae3 100644
--- a/src/Makefile_Elementary.am
+++ b/src/Makefile_Elementary.am
@@ -117,6 +117,7 @@ elm_public_eolian_files = \
lib/elementary/efl_ui_text_editable.eo \
lib/elementary/efl_config_global.eo \
lib/elementary/efl_ui_clock.eo \
+ lib/elementary/efl_ui_image_factory.eo \
$(NULL)
# Private classes (not exposed or shipped)
@@ -667,6 +668,7 @@ lib_elementary_libelementary_la_SOURCES = \
lib/elementary/efl_ui_text.c \
lib/elementary/efl_ui_clock.c \
lib/elementary/efl_ui_clock_private.h \
+ lib/elementary/efl_ui_image_factory.c \
$(NULL)
diff --git a/src/examples/elementary/Makefile.am b/src/examples/elementary/Makefile.am
index 6f7cd33d69..020f7076df 100644
--- a/src/examples/elementary/Makefile.am
+++ b/src/examples/elementary/Makefile.am
@@ -117,6 +117,7 @@ label_example_01.c \
layout_example_01.c \
layout_example_02.c \
layout_example_03.c \
+layout_model_connect.c \
list_example_01.c \
list_example_02.c \
list_example_03.c \
@@ -318,6 +319,7 @@ label_example_01 \
layout_example_01 \
layout_example_02 \
layout_example_03 \
+layout_model_connect \
list_example_01 \
list_example_02 \
list_example_03 \
diff --git a/src/examples/elementary/layout_model_connect.c b/src/examples/elementary/layout_model_connect.c
new file mode 100644
index 0000000000..012832c45b
--- /dev/null
+++ b/src/examples/elementary/layout_model_connect.c
@@ -0,0 +1,176 @@
+// gcc -o layout_model_connect layout_model_connect.c `pkg-config --cflags --libs elementary`
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#else
+# define EFL_BETA_API_SUPPORT 1
+# define EFL_EO_API_SUPPORT 1
+#endif
+
+#include <Elementary.h>
+#include <Efl.h>
+#include <Eio.h>
+#include <stdio.h>
+
+#define EFL_MODEL_TEST_FILENAME_PATH "/tmp"
+
+struct _Layout_Model_Data
+{
+ Eo *fileview;
+ Eo *model;
+ Evas_Object *label;
+ Evas_Object *entry;
+ Evas_Object *img;
+ Evas_Object *bt;
+};
+typedef struct _Layout_Model_Data Layout_Model_Data;
+
+static void
+_cleanup_cb(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
+{
+ Layout_Model_Data *priv = (Layout_Model_Data*)data;
+ efl_unref(priv->fileview);
+ efl_unref(priv->model);
+}
+
+static void
+_list_selected_cb(void *data EINA_UNUSED, const Efl_Event *event)
+{
+ Layout_Model_Data *priv = data;
+ Eo *child = event->info;
+
+ printf("LIST selected model\n");
+ efl_ui_view_model_set(priv->label, child);
+ efl_ui_view_model_set(priv->entry, child);
+ efl_ui_view_model_set(priv->img, child);
+ efl_ui_view_model_set(priv->bt, child);
+}
+
+
+static void
+_update_cb(void *data, Evas_Object *obj, void *ev)
+{
+ Layout_Model_Data *priv = data;
+
+ const char *text = elm_object_text_get(priv->entry);
+ elm_layout_text_set(priv->label, "default", text);
+}
+
+static void
+_widget_init(Evas_Object *widget)
+{
+ evas_object_size_hint_weight_set(widget, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+ evas_object_size_hint_align_set(widget, EVAS_HINT_FILL, EVAS_HINT_FILL);
+ evas_object_show(widget);
+}
+
+Evas_Object *
+_label_init(Evas_Object *win, Evas_Object *box, const char *text)
+{
+ Evas_Object *widget = elm_label_add(win);
+ elm_label_line_wrap_set(widget, ELM_WRAP_CHAR);
+ elm_object_text_set(widget, text);
+ elm_box_pack_end(box, widget);
+ evas_object_size_hint_weight_set(widget, EVAS_HINT_FILL, EVAS_HINT_FILL);
+ evas_object_size_hint_align_set(widget, EVAS_HINT_FILL, EVAS_HINT_FILL);
+ evas_object_show(widget);
+
+ return widget;
+}
+
+
+static void
+_signal_cb(void *data,
+ Evas_Object *obj EINA_UNUSED,
+ const char *emission,
+ const char *source)
+{
+ printf(">> Signal callback emission='%s' source='%s'\n", emission, source);
+}
+
+EAPI_MAIN int
+elm_main(int argc, char **argv)
+{
+ Layout_Model_Data *priv;
+ Evas_Object *win, *panes, *bxr, *genlist;
+ Eo *img_factory;
+ char *dirname;
+
+ priv = alloca(sizeof(Layout_Model_Data));
+ memset(priv, 0, sizeof(Layout_Model_Data));
+
+ //win
+ win = elm_win_util_standard_add("viewlist", "Viewlist");
+ elm_policy_set(ELM_POLICY_QUIT, ELM_POLICY_QUIT_LAST_WINDOW_CLOSED);
+ elm_win_autodel_set(win, EINA_TRUE);
+
+ panes = elm_panes_add(win);
+ evas_object_size_hint_weight_set(panes, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+ elm_win_resize_object_add(win, panes);
+
+ if (argv[1] != NULL) dirname = argv[1];
+ else dirname = EFL_MODEL_TEST_FILENAME_PATH;
+
+ priv->model = efl_add(EIO_MODEL_CLASS, NULL, eio_model_path_set(efl_added, dirname));
+
+ genlist = elm_genlist_add(win);
+ priv->fileview = efl_add(ELM_VIEW_LIST_CLASS, NULL, elm_view_list_genlist_set(efl_added, genlist, ELM_GENLIST_ITEM_NONE, NULL));
+ elm_view_list_property_connect(priv->fileview, "filename", "elm.text");
+ elm_view_list_model_set(priv->fileview, priv->model);
+ _widget_init(genlist);
+ elm_object_part_content_set(panes, "left", genlist);
+ elm_obj_panes_content_left_size_set(panes, 0.3);
+ efl_event_callback_add(priv->fileview, ELM_VIEW_LIST_EVENT_MODEL_SELECTED, _list_selected_cb, priv);
+
+ bxr = elm_box_add(win);
+ _widget_init(bxr);
+ elm_object_part_content_set(panes, "right", bxr);
+
+ /*Label widget */
+
+ _label_init(win, bxr, "FILENAME:");
+ priv->label = _label_init(win, bxr, "");
+ efl_ui_model_connect(priv->label, "default", "path"); //connect "default" to "filename" property
+
+ /* Entry widget */
+ priv->entry = elm_entry_add(win);
+ efl_ui_model_connect(priv->entry, "elm.text", "path"); //connect "elm.text" to "path" property
+ elm_entry_single_line_set(priv->entry, EINA_TRUE);
+ elm_box_pack_end(bxr, priv->entry);
+ evas_object_size_hint_weight_set(priv->entry, EVAS_HINT_FILL, 0);
+ evas_object_size_hint_align_set(priv->entry, EVAS_HINT_FILL, EVAS_HINT_FILL);
+ evas_object_show(priv->entry);
+
+ /* Button widget */
+ priv->bt = elm_button_add(win);
+ elm_box_pack_end(bxr, priv->bt);
+ elm_object_text_set(priv->bt, "update model");
+ evas_object_smart_callback_add(priv->bt, "clicked", _update_cb, priv);
+ edje_obj_signal_callback_add(priv->bt, "test*" , "*", _signal_cb, priv);
+ efl_ui_model_connect(priv->bt, "signal/test-%v", "size");
+ evas_object_show(priv->bt);
+
+ /* Image widget */
+ img_factory = efl_add(EFL_UI_IMAGE_FACTORY_CLASS, win);
+ efl_ui_model_connect(img_factory, "", "path"); //connect to "path" property
+ efl_ui_model_factory_connect(priv->bt, "icon", img_factory);
+
+ priv->img = efl_ui_factory_create(img_factory, NULL, win);
+ elm_box_pack_end(bxr, priv->img);
+ evas_object_size_hint_weight_set(priv->img, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+ evas_object_size_hint_align_set(priv->img, EVAS_HINT_FILL, EVAS_HINT_FILL);
+ evas_object_show(priv->img);
+
+ evas_object_event_callback_add(win, EVAS_CALLBACK_DEL, _cleanup_cb, priv);
+ //showall
+ evas_object_resize(win, 800, 400);
+ evas_object_show(panes);
+ evas_object_show(win);
+
+ elm_run();
+ elm_shutdown();
+ ecore_shutdown();
+
+ return 0;
+}
+ELM_MAIN()
diff --git a/src/lib/ecore/Ecore_Eo.h b/src/lib/ecore/Ecore_Eo.h
index 1387afb344..1c29de392c 100644
--- a/src/lib/ecore/Ecore_Eo.h
+++ b/src/lib/ecore/Ecore_Eo.h
@@ -116,6 +116,20 @@ EAPI Efl_Future *efl_future_iterator_race(Eina_Iterator *it);
* @}
*/
+/**
+ * @ingroup Ecore_Model_Group
+ *
+ * @{
+ */
+
+#include "efl_model_item.eo.h"
+#include "efl_model_container.eo.h"
+#include "efl_model_container_item.eo.h"
+
+/**
+ * @}
+ */
+
#ifdef __cplusplus
}
diff --git a/src/lib/ecore/efl_model_container.c b/src/lib/ecore/efl_model_container.c
new file mode 100644
index 0000000000..69a5704353
--- /dev/null
+++ b/src/lib/ecore/efl_model_container.c
@@ -0,0 +1,298 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <Efl.h>
+#include <Eina.h>
+#include <Eo.h>
+#include <Ecore.h>
+
+#include "efl_model_container_private.h"
+
+#define MY_CLASS EFL_MODEL_CONTAINER_CLASS
+
+void *
+_value_copy_alloc(void *v, const Eina_Value_Type *type)
+{
+ if (!v)
+ return v;
+
+ if (type == EINA_VALUE_TYPE_STRINGSHARE)
+ return (void*) eina_stringshare_ref(v);
+ else if (type == EINA_VALUE_TYPE_STRING)
+ return (void*) strdup(v);
+ else
+ {
+ void *ret = malloc(type->value_size);
+ memcpy(ret, v, type->value_size);
+ return ret;
+ }
+}
+
+void
+_value_free(void *v, const Eina_Value_Type *type)
+{
+ if (!v)
+ return;
+
+ if (type == EINA_VALUE_TYPE_STRINGSHARE)
+ return eina_stringshare_del(v);
+ else
+ free(v);
+}
+
+static void
+_values_free(Eina_Array *values, const Eina_Value_Type *type)
+{
+ unsigned int i;
+ void *v;
+ Eina_Array_Iterator it;
+ EINA_ARRAY_ITER_NEXT(values, i, v, it)
+ {
+ _value_free(v, type);
+ }
+ eina_array_free(values);
+}
+
+static Eina_Bool
+_stringshared_keys_free(const Eina_Hash *hash EINA_UNUSED, const void *key, void *data EINA_UNUSED, void *fdata EINA_UNUSED)
+{
+ eina_stringshare_del(key);
+ return EINA_TRUE;
+}
+
+static void
+_property_data_free_cb(void *data)
+{
+ Child_Property_Data *cpd = data;
+ _values_free(cpd->property_values, cpd->property_type);
+ free(cpd);
+}
+
+static Efl_Object *
+_efl_model_container_efl_object_constructor(Eo *obj, Efl_Model_Container_Data *sd)
+{
+ obj = efl_constructor(efl_super(obj, MY_CLASS));
+ if (!obj)
+ return NULL;
+
+ sd->obj = obj;
+ sd->property_data = eina_hash_stringshared_new(_property_data_free_cb);
+ sd->defined_properties = eina_array_new(8);
+
+ return obj;
+}
+
+static void
+_efl_model_container_efl_object_destructor(Eo *obj, Efl_Model_Container_Data *sd)
+{
+ Efl_Model *child;
+
+ EINA_LIST_FREE(sd->children, child)
+ {
+ if (child)
+ {
+ efl_model_container_item_invalidate(child);
+ efl_parent_set(child, NULL);
+ }
+ }
+
+ eina_array_free(sd->defined_properties);
+
+ eina_hash_foreach(sd->property_data, _stringshared_keys_free, NULL);
+ eina_hash_free(sd->property_data);
+
+ efl_destructor(efl_super(obj, MY_CLASS));
+}
+
+static const Eina_Value_Type *
+_efl_model_container_child_property_value_type_get(Eo *obj EINA_UNUSED, Efl_Model_Container_Data *sd, const char *property)
+{
+ Eina_Stringshare *sshared = eina_stringshare_add(property);
+ Child_Property_Data *cpd = eina_hash_find(sd->property_data, sshared);
+ eina_stringshare_del(sshared);
+ if (!cpd)
+ return NULL;
+
+ return cpd->property_type;
+}
+
+static Eina_Iterator *
+_efl_model_container_child_property_values_get(Eo *obj EINA_UNUSED, Efl_Model_Container_Data *sd, const char *property)
+{
+ Eina_Stringshare *sshared = eina_stringshare_add(property);
+ Child_Property_Data *cpd = eina_hash_find(sd->property_data, sshared);
+ eina_stringshare_del(sshared);
+ if (!cpd)
+ return NULL;
+
+ return eina_array_iterator_new(cpd->property_values);
+}
+
+static Eina_Bool
+_efl_model_container_child_property_add(Eo *obj, Efl_Model_Container_Data *sd, const char *name, const Eina_Value_Type *type, Eina_Iterator *values)
+{
+ Eina_Array *arr = NULL;
+ void *data = NULL;
+ Eina_Stringshare *prop_name = NULL;
+ Child_Property_Data *cpd = NULL;
+ unsigned int i, in_count, children_count;
+
+ if (!type || !values)
+ {
+ EINA_LOG_WARN("Invalid input data");
+ eina_error_set(EFL_MODEL_ERROR_INCORRECT_VALUE);
+ return EINA_FALSE;
+ }
+
+ arr = eina_array_new(32);
+ if (!arr)
+ {
+ eina_error_set(EFL_MODEL_ERROR_UNKNOWN);
+ return EINA_FALSE;
+ }
+
+ EINA_ITERATOR_FOREACH(values, data)
+ {
+ void *new_data = _value_copy_alloc(data, type);
+ if ((data && !new_data) || !eina_array_push(arr, new_data))
+ {
+ if (new_data)
+ _value_free(new_data, type);
+ goto error;
+ }
+ }
+ eina_iterator_free(values);
+
+ prop_name = eina_stringshare_add(name);
+ cpd = eina_hash_find(sd->property_data, prop_name);
+ if (!cpd)
+ {
+ cpd = calloc(1, sizeof(Child_Property_Data));
+ if (!cpd)
+ goto error;
+
+ cpd->property_type = type;
+ cpd->property_values = arr;
+
+ if (!eina_array_push(sd->defined_properties, prop_name))
+ goto error;
+
+ if (!eina_hash_direct_add(sd->property_data, prop_name, cpd))
+ {
+ eina_array_pop(sd->defined_properties);
+ goto error;
+ }
+ }
+ else
+ {
+ eina_stringshare_del(prop_name);
+ _values_free(cpd->property_values, cpd->property_type);
+
+ cpd->property_type = type;
+ cpd->property_values = arr;
+ }
+
+ in_count = eina_array_count(arr);
+ children_count = eina_list_count(sd->children);
+
+ for (i = children_count; i < in_count; ++i)
+ {
+ Efl_Model_Children_Event cevt;
+ Efl_Model *child;
+
+ child = efl_add(EFL_MODEL_CONTAINER_ITEM_CLASS, obj,
+ efl_model_container_item_define(efl_added, sd, i));
+ sd->children = eina_list_append(sd->children, child);
+
+ cevt.child = child;
+ cevt.index = i;
+ efl_event_callback_call(obj, EFL_MODEL_EVENT_CHILD_ADDED, &cevt);
+ }
+
+ if (in_count > children_count)
+ efl_event_callback_call(obj, EFL_MODEL_EVENT_CHILDREN_COUNT_CHANGED, &in_count);
+
+ return EINA_TRUE;
+
+error:
+ if (prop_name)
+ eina_stringshare_del(prop_name);
+ if (cpd)
+ free(cpd);
+ if (arr)
+ _values_free(arr, type);
+ eina_error_set(EFL_MODEL_ERROR_UNKNOWN);
+ return EINA_FALSE;
+}
+
+static const Eina_Array *
+_efl_model_container_efl_model_properties_get(Eo *obj EINA_UNUSED, Efl_Model_Container_Data *sd EINA_UNUSED)
+{
+ return sd->defined_properties;
+}
+
+
+Efl_Future *
+_efl_model_container_efl_model_property_set(Eo *obj EINA_UNUSED, Efl_Model_Container_Data *sd EINA_UNUSED, const char *property EINA_UNUSED, const Eina_Value *value EINA_UNUSED)
+{
+ Efl_Promise *promise = efl_add(EFL_PROMISE_CLASS, ecore_main_loop_get());
+ Efl_Future* future = efl_promise_future_get(promise);
+
+ efl_promise_failed_set(promise, EFL_MODEL_ERROR_NOT_FOUND);
+ return future;
+}
+
+Efl_Future *
+_efl_model_container_efl_model_property_get(Eo *obj EINA_UNUSED, Efl_Model_Container_Data *sd EINA_UNUSED, const char *property EINA_UNUSED)
+{
+
+ Efl_Promise *promise = efl_add(EFL_PROMISE_CLASS, ecore_main_loop_get());
+ Efl_Future* future = efl_promise_future_get(promise);
+
+ efl_promise_failed_set(promise, EFL_MODEL_ERROR_NOT_FOUND);
+ return future;
+}
+
+static Efl_Future *
+_efl_model_container_efl_model_children_slice_get(Eo *obj EINA_UNUSED, Efl_Model_Container_Data *sd, unsigned int start, unsigned int count)
+{
+ Efl_Promise *promise = efl_add(EFL_PROMISE_CLASS, ecore_main_loop_get());
+ Efl_Future* future = efl_promise_future_get(promise);
+
+ Eina_Accessor* accessor = efl_model_list_slice(sd->children, start, count);
+ efl_promise_value_set(promise, accessor, (Eina_Free_Cb)&eina_accessor_free);
+
+ return future;
+}
+
+static Efl_Future *
+_efl_model_container_efl_model_children_count_get(Eo *obj EINA_UNUSED, Efl_Model_Container_Data *sd)
+{
+ Efl_Promise *promise = efl_add(EFL_PROMISE_CLASS, ecore_main_loop_get());
+ Efl_Future* future = efl_promise_future_get(promise);
+
+ unsigned int *count = calloc(1, sizeof(unsigned int));
+ *count = eina_list_count(sd->children);
+ efl_promise_value_set(promise, count, &free);
+
+ return future;
+}
+
+static Eo *
+_efl_model_container_efl_model_child_add(Eo *obj EINA_UNUSED, Efl_Model_Container_Data *sd EINA_UNUSED)
+{
+ EINA_LOG_WARN("child_add not supported by Efl.Model.Container");
+ eina_error_set(EFL_MODEL_ERROR_NOT_SUPPORTED);
+
+ return NULL;
+}
+
+static void
+_efl_model_container_efl_model_child_del(Eo *obj EINA_UNUSED, Efl_Model_Container_Data *sd EINA_UNUSED, Eo *child EINA_UNUSED)
+{
+ EINA_LOG_WARN("child_del not supported by Efl.Model.Container");
+ eina_error_set(EFL_MODEL_ERROR_NOT_SUPPORTED);
+}
+
+#include "efl_model_container.eo.c"
diff --git a/src/lib/ecore/efl_model_container.eo b/src/lib/ecore/efl_model_container.eo
new file mode 100644
index 0000000000..baee70735d
--- /dev/null
+++ b/src/lib/ecore/efl_model_container.eo
@@ -0,0 +1,60 @@
+import eina_types;
+
+class Efl.Model.Container (Efl.Object, Efl.Model)
+{
+ [[
+ Class used to create data models from Eina containers.
+
+ Each container supplied represent a series of property values, each item
+ being the property value for a child object (@Efl.Model.Container.Item).
+
+ The data in the given containers are copied and stored internally.
+
+ Several containers can be supplied, and the number of allocated children is
+ based on the container with the biggest size.
+ ]]
+ methods {
+ child_property_value_type_get {
+ [[Get the type of the given property.]]
+ params {
+ name: string; [[Property name]]
+ }
+ return: ptr(const(Eina.Value.Type)); [[Property type]]
+ }
+ child_property_values_get {
+ [[Get the values for the given property.]]
+ params {
+ name: string; [[Property name]]
+ }
+ return: free(own(iterator<void_ptr>), eina_iterator_free) @warn_unused;
+ [[The currently wrapped values]]
+ }
+ child_property_add {
+ [[Add the given property to child objects and supply the values.
+
+ Each item will represent the value of the given property in the
+ respective child within the data model.
+
+ New children objects are allocated as necessary.
+
+ Value type is required for compatibility with the @Efl.Model API.]]
+ params {
+ name: string; [[Property name]]
+ type: ptr(const(Eina.Value.Type)); [[Property type]]
+ values: own(iterator<const(void_ptr)>); [[Values to be added]]
+ }
+ return: bool; [[$true on success, $false otherwise]]
+ }
+ }
+ implements {
+ Efl.Object.constructor;
+ Efl.Object.destructor;
+ Efl.Model.properties { get; }
+ Efl.Model.property_set;
+ Efl.Model.property_get;
+ Efl.Model.child_add;
+ Efl.Model.child_del;
+ Efl.Model.children_slice_get;
+ Efl.Model.children_count_get;
+ }
+}
diff --git a/src/lib/ecore/efl_model_container_item.c b/src/lib/ecore/efl_model_container_item.c
new file mode 100644
index 0000000000..945c0c9ce0
--- /dev/null
+++ b/src/lib/ecore/efl_model_container_item.c
@@ -0,0 +1,192 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <Efl.h>
+#include <Ecore.h>
+
+#include "efl_model_container_private.h"
+
+#define MY_CLASS EFL_MODEL_CONTAINER_ITEM_CLASS
+
+static void
+_item_value_free_cb(void *data)
+{
+ eina_value_free(data);
+}
+
+EOLIAN static void
+_efl_model_container_item_define(Eo *obj EINA_UNUSED, Efl_Model_Container_Item_Data *sd, void *parent_data, unsigned int index)
+{
+ sd->parent_data = parent_data;
+ sd->index = index;
+}
+
+EOLIAN static void
+_efl_model_container_item_invalidate(Eo *obj EINA_UNUSED, Efl_Model_Container_Item_Data *sd)
+{
+ sd->parent_data = NULL;
+ sd->index = 0;
+}
+
+EOLIAN static const Eina_Array *
+_efl_model_container_item_efl_model_properties_get(Eo *obj EINA_UNUSED, Efl_Model_Container_Item_Data *sd)
+{
+ if (!sd->parent_data)
+ return NULL;
+
+ return sd->parent_data->defined_properties;
+}
+
+Efl_Future *
+_efl_model_container_item_efl_model_property_set(Eo *obj EINA_UNUSED, Efl_Model_Container_Item_Data *sd, const char *property, const Eina_Value *value)
+{
+ Eina_Stringshare *prop_name;
+ Child_Property_Data *cpd;
+ void *data, *new_data;
+ Efl_Promise *promise = efl_add(EFL_PROMISE_CLASS, ecore_main_loop_get());
+ Efl_Future* future = efl_promise_future_get(promise);
+
+ if (!sd->parent_data)
+ {
+ efl_promise_failed_set(promise, EFL_MODEL_ERROR_INVALID_OBJECT);
+ return future;
+ }
+
+ prop_name = eina_stringshare_add(property);
+ cpd = eina_hash_find(sd->parent_data->property_data, prop_name);
+ eina_stringshare_del(prop_name);
+ if (!cpd || !cpd->property_values ||
+ sd->index >= eina_array_count_get(cpd->property_values))
+ {
+ efl_promise_failed_set(promise, EFL_MODEL_ERROR_NOT_FOUND);
+ return future;
+ }
+
+ if (cpd->property_type != eina_value_type_get(value))
+ {
+ efl_promise_failed_set(promise, EFL_MODEL_ERROR_INCORRECT_VALUE);
+ return future;
+ }
+
+ data = calloc(1, cpd->property_type->value_size);
+ if (!data || !eina_value_pget(value, data))
+ {
+ if (data)
+ free(data);
+ efl_promise_failed_set(promise, EFL_MODEL_ERROR_UNKNOWN);
+ return future;
+ }
+
+ new_data = _value_copy_alloc(data, cpd->property_type);
+ free(data);
+
+ _value_free(eina_array_data_get(cpd->property_values, sd->index), cpd->property_type);
+ eina_array_data_set(cpd->property_values, sd->index, new_data);
+
+ {
+ Eina_Value *v = eina_value_new(cpd->property_type);
+ if (v && eina_value_copy(value, v))
+ efl_promise_value_set(promise, v, _item_value_free_cb);
+ else
+ {
+ if (v)
+ eina_value_free(v);
+ efl_promise_failed_set(promise, EFL_MODEL_ERROR_UNKNOWN);
+ }
+ }
+
+ return future;
+}
+
+Efl_Future *
+_efl_model_container_item_efl_model_property_get(Eo *obj EINA_UNUSED, Efl_Model_Container_Item_Data *sd, const char *property)
+{
+ Eina_Stringshare *prop_name;
+ Child_Property_Data *cpd;
+ Eina_Value *value;
+ Efl_Promise *promise = efl_add(EFL_PROMISE_CLASS, ecore_main_loop_get());
+ Efl_Future* future = efl_promise_future_get(promise);
+
+ if (!sd->parent_data)
+ {
+ efl_promise_failed_set(promise, EFL_MODEL_ERROR_INVALID_OBJECT);
+ return future;
+ }
+
+ prop_name = eina_stringshare_add(property);
+ cpd = eina_hash_find(sd->parent_data->property_data, prop_name);
+ eina_stringshare_del(prop_name);
+ if (!cpd || !cpd->property_values ||
+ sd->index >= eina_array_count_get(cpd->property_values))
+ {
+ efl_promise_failed_set(promise, EFL_MODEL_ERROR_NOT_FOUND);
+ return future;
+ }
+
+ value = eina_value_new(cpd->property_type);
+ if (!value)
+ efl_promise_failed_set(promise, EFL_MODEL_ERROR_UNKNOWN);
+ else
+ {
+ Eina_Bool r = EINA_FALSE;
+ void *data = eina_array_data_get(cpd->property_values, sd->index);
+
+ if (cpd->property_type == EINA_VALUE_TYPE_STRINGSHARE ||
+ cpd->property_type == EINA_VALUE_TYPE_STRING)
+ r = eina_value_set(value, data);
+ else
+ r = eina_value_pset(value, data);
+
+ if (r)
+ efl_promise_value_set(promise, value, _item_value_free_cb);
+ else
+ {
+ efl_promise_failed_set(promise, EFL_MODEL_ERROR_UNKNOWN);
+ eina_value_free(value);
+ }
+ }
+ return future;
+}
+
+EOLIAN static Efl_Future *
+_efl_model_container_item_efl_model_children_slice_get(Eo *obj EINA_UNUSED, Efl_Model_Container_Item_Data *sd EINA_UNUSED, unsigned int start EINA_UNUSED, unsigned int count EINA_UNUSED)
+{
+ Efl_Promise *promise = efl_add(EFL_PROMISE_CLASS, ecore_main_loop_get());
+ Efl_Future* future = efl_promise_future_get(promise);
+
+ efl_promise_value_set(promise, NULL, NULL);
+
+ return future;
+}
+
+EOLIAN static Efl_Future *
+_efl_model_container_item_efl_model_children_count_get(Eo *obj EINA_UNUSED, Efl_Model_Container_Item_Data *sd EINA_UNUSED)
+{
+ Efl_Promise *promise = efl_add(EFL_PROMISE_CLASS, ecore_main_loop_get());
+ Efl_Future* future = efl_promise_future_get(promise);
+
+ unsigned int *count = calloc(1, sizeof(unsigned int));
+ *count = 0;
+ efl_promise_value_set(promise, count, &free);
+
+ return future;
+}
+
+EOLIAN static Eo *
+_efl_model_container_item_efl_model_child_add(Eo *obj EINA_UNUSED, Efl_Model_Container_Item_Data *sd EINA_UNUSED)
+{
+ EINA_LOG_WARN("child_add not supported by Efl.Model.Container.Item");
+ eina_error_set(EFL_MODEL_ERROR_NOT_SUPPORTED);
+
+ return NULL;
+}
+
+EOLIAN static void
+_efl_model_container_item_efl_model_child_del(Eo *obj EINA_UNUSED, Efl_Model_Container_Item_Data *sd EINA_UNUSED, Eo *child EINA_UNUSED)
+{
+ EINA_LOG_WARN("child_del not supported by Efl.Model.Container.Item");
+ eina_error_set(EFL_MODEL_ERROR_NOT_SUPPORTED);
+}
+
+#include "efl_model_container_item.eo.c"
diff --git a/src/lib/ecore/efl_model_container_item.eo b/src/lib/ecore/efl_model_container_item.eo
new file mode 100644
index 0000000000..94314357ad
--- /dev/null
+++ b/src/lib/ecore/efl_model_container_item.eo
@@ -0,0 +1,39 @@
+import eina_types;
+
+class Efl.Model.Container.Item (Efl.Object, Efl.Model)
+{
+ [[
+ Used as a child of @Efl.Model.Container.
+
+ Provides the @Efl.Model API for elements of @Efl.Model.Container.
+ Should not be used in another context, so do not manually create objects
+ of this class.
+ ]]
+ methods {
+ define {
+ [[Define @Efl.Model.Container.Item internal data.]]
+ params {
+ parent_data: void_ptr; [[Pointer to the private data of the
+ @Efl.Model.Container parent object.]]
+ index: uint; [[Index of this item within the @Efl.Model.Container
+ children.]]
+ }
+ }
+ invalidate {
+ [[Invalidate the object preventing it from using the given parent
+ data.]]
+ }
+ }
+ implements {
+ Efl.Model.properties { get; }
+ Efl.Model.property_set;
+ Efl.Model.property_get;
+ Efl.Model.child_add;
+ Efl.Model.child_del;
+ Efl.Model.children_slice_get;
+ Efl.Model.children_count_get;
+ }
+ constructors {
+ .define;
+ }
+}
diff --git a/src/lib/ecore/efl_model_container_private.h b/src/lib/ecore/efl_model_container_private.h
new file mode 100644
index 0000000000..0a0aad1be6
--- /dev/null
+++ b/src/lib/ecore/efl_model_container_private.h
@@ -0,0 +1,32 @@
+#ifndef EFL_MODEL_PRIVATE_H__
+# define EFL_MODEL_PRIVATE_H__
+
+typedef struct _Child_Property_Data Child_Property_Data;
+struct _Child_Property_Data
+{
+ const Eina_Value_Type *property_type;
+ Eina_Array *property_values;
+};
+
+typedef struct _Efl_Model_Container_Data Efl_Model_Container_Data;
+struct _Efl_Model_Container_Data
+{
+ Eo *obj;
+ Eina_Hash *property_data;
+ Eina_Array *defined_properties;
+ Eina_List *children;
+};
+
+
+typedef struct _Efl_Model_Container_Item_Data Efl_Model_Container_Item_Data;
+struct _Efl_Model_Container_Item_Data
+{
+ Efl_Model_Container_Data *parent_data;
+ unsigned int index;
+};
+
+void *_value_copy_alloc(void *v, const Eina_Value_Type *type);
+
+void _value_free(void *v, const Eina_Value_Type *type);
+
+#endif
diff --git a/src/lib/ecore/efl_model_item.c b/src/lib/ecore/efl_model_item.c
new file mode 100644
index 0000000000..d8566d9107
--- /dev/null
+++ b/src/lib/ecore/efl_model_item.c
@@ -0,0 +1,202 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <Efl.h>
+#include <Ecore.h>
+
+#define MY_CLASS EFL_MODEL_ITEM_CLASS
+
+typedef struct _Efl_Model_Item_Data Efl_Model_Item_Data;
+struct _Efl_Model_Item_Data
+{
+ Eina_Hash *properties;
+ Eina_Array *defined_properties;
+ Eina_List *children;
+};
+
+static void
+_item_value_free_cb(void *data)
+{
+ eina_value_free(data);
+}
+
+static Eina_Bool
+_stringshared_keys_free(const Eina_Hash *hash EINA_UNUSED, const void *key, void *data EINA_UNUSED, void *fdata EINA_UNUSED)
+{
+ eina_stringshare_del(key);
+ return EINA_TRUE;
+}
+
+static Efl_Object *
+_efl_model_item_efl_object_constructor(Eo *obj, Efl_Model_Item_Data *sd)
+{
+ obj = efl_constructor(efl_super(obj, MY_CLASS));
+ if (!obj)
+ return NULL;
+
+ sd->properties = eina_hash_stringshared_new(_item_value_free_cb);
+ sd->defined_properties = eina_array_new(8);
+
+ return obj;
+}
+
+static void
+_efl_model_item_efl_object_destructor(Eo *obj, Efl_Model_Item_Data *sd)
+{
+ Efl_Model *child;
+
+ EINA_LIST_FREE(sd->children, child)
+ {
+ if (child)
+ efl_parent_set(child, NULL);
+ }
+
+ eina_hash_foreach(sd->properties, _stringshared_keys_free, NULL);
+ eina_hash_free(sd->properties);
+
+ eina_array_free(sd->defined_properties);
+
+ efl_destructor(efl_super(obj, MY_CLASS));
+}
+
+EOLIAN static const Eina_Array *
+_efl_model_item_efl_model_properties_get(Eo *obj EINA_UNUSED, Efl_Model_Item_Data *sd)
+{
+ return sd->defined_properties;
+}
+
+
+static Efl_Future*
+_efl_model_item_efl_model_property_set(Eo *obj EINA_UNUSED, Efl_Model_Item_Data *sd, const char *property, const Eina_Value *value)
+{
+ Efl_Promise *promise = efl_add(EFL_PROMISE_CLASS, ecore_main_loop_get());
+ Efl_Future* future = efl_promise_future_get(promise);
+
+ Eina_Stringshare *sshared = eina_stringshare_add(property);
+ Eina_Value *p_v = eina_hash_find(sd->properties, sshared);
+ if (p_v)
+ {
+ eina_stringshare_del(sshared);
+ if (!eina_value_copy(value, p_v))
+ goto err1;
+ }
+ else
+ {
+ if (!eina_array_push(sd->defined_properties, sshared))
+ goto err2;
+
+ p_v = eina_value_new(eina_value_type_get(value));
+ if (!p_v)
+ goto err3;
+
+ if (!eina_value_copy(value, p_v) ||
+ !eina_hash_direct_add(sd->properties, sshared, p_v))
+ goto err4;
+ }
+
+ efl_promise_value_set(promise, p_v, NULL);
+ return future;
+
+err4:
+ eina_value_free(p_v);
+err3:
+ eina_array_pop(sd->defined_properties);
+err2:
+ eina_stringshare_del(sshared);
+err1:
+ efl_promise_failed_set(promise, EFL_MODEL_ERROR_UNKNOWN);
+ return future;
+}
+
+static Efl_Future *
+_efl_model_item_efl_model_property_get(Eo *obj EINA_UNUSED, Efl_Model_Item_Data *sd, const char *property)
+{
+ Efl_Promise *promise = efl_add(EFL_PROMISE_CLASS, ecore_main_loop_get());
+ Efl_Future *rfuture = efl_promise_future_get(promise);
+
+ Eina_Stringshare *sshare = eina_stringshare_add(property);
+ Eina_Value *p_v = eina_hash_find(sd->properties, sshare);
+ eina_stringshare_del(sshare);
+ if (p_v)
+ efl_promise_value_set(promise, p_v, NULL);
+ else
+ efl_promise_failed_set(promise, EFL_MODEL_ERROR_NOT_FOUND);
+
+ return rfuture;
+}
+
+static Efl_Future *
+_efl_model_item_efl_model_children_slice_get(Eo *obj EINA_UNUSED, Efl_Model_Item_Data *sd, unsigned int start, unsigned int count)
+{
+ Efl_Promise *promise = efl_add(EFL_PROMISE_CLASS, ecore_main_loop_get());
+ Efl_Future *rfuture = efl_promise_future_get(promise);
+
+ Eina_Accessor* accessor = efl_model_list_slice(sd->children, start, count);
+ efl_promise_value_set(promise, accessor, (Eina_Free_Cb)&eina_accessor_free);
+
+ return rfuture;
+}
+
+static Efl_Future *
+_efl_model_item_efl_model_children_count_get(Eo *obj EINA_UNUSED, Efl_Model_Item_Data *sd)
+{
+ Efl_Promise *promise = efl_add(EFL_PROMISE_CLASS, ecore_main_loop_get());
+ Efl_Future *rfuture = efl_promise_future_get(promise);
+
+ unsigned int *count = calloc(1, sizeof(unsigned int));
+ *count = eina_list_count(sd->children);
+ efl_promise_value_set(promise, count, &free);
+
+ return rfuture;
+}
+
+static Eo *
+_efl_model_item_efl_model_child_add(Eo *obj, Efl_Model_Item_Data *sd)
+{
+ Efl_Model_Children_Event cevt;
+ Efl_Model *child = efl_add(EFL_MODEL_ITEM_CLASS, obj);
+ if (!child)
+ {
+ EINA_LOG_ERR("Could not allocate Efl.Model.Item");
+ eina_error_set(EFL_MODEL_ERROR_UNKNOWN);
+ return NULL;
+ }
+ sd->children = eina_list_append(sd->children, child);
+ cevt.child = child;
+ cevt.index = eina_list_count(sd->children);
+ efl_event_callback_call(obj, EFL_MODEL_EVENT_CHILD_ADDED, &cevt);
+ efl_event_callback_call(obj, EFL_MODEL_EVENT_CHILDREN_COUNT_CHANGED, &cevt.index);
+ return child;
+}
+
+static void
+_efl_model_item_efl_model_child_del(Eo *obj, Efl_Model_Item_Data *sd, Eo *child)
+{
+ Eina_List *l;
+ Efl_Model *data;
+ unsigned int i = 0;
+ EINA_LIST_FOREACH(sd->children, l, data)
+ {
+ if (data == child)
+ {
+ Efl_Model_Children_Event cevt;
+ sd->children = eina_list_remove_list(sd->children, l);
+
+ cevt.child = efl_ref(child);
+ cevt.index = i;
+
+ efl_parent_set(child, NULL);
+
+ efl_event_callback_call(obj, EFL_MODEL_EVENT_CHILD_REMOVED, &cevt);
+ efl_unref(child);
+
+ i = eina_list_count(sd->children);
+ efl_event_callback_call(obj, EFL_MODEL_EVENT_CHILDREN_COUNT_CHANGED, &i);
+ break;
+ }
+ ++i;
+ }
+}
+
+#include "efl_model_item.eo.c"
diff --git a/src/lib/ecore/efl_model_item.eo b/src/lib/ecore/efl_model_item.eo
new file mode 100644
index 0000000000..622cd249cb
--- /dev/null
+++ b/src/lib/ecore/efl_model_item.eo
@@ -0,0 +1,26 @@
+import eina_types;
+
+class Efl.Model.Item (Efl.Object, Efl.Model)
+{
+ [[
+ Generic model that allows any property to be manually set.
+ Also children of the same type can be added and deleted.
+
+ Intended to be used in scenarios where the user needs a manually defined
+ data model, like in tests.
+
+ It does not model anything in particular and does not affect anything else
+ in the system.
+ ]]
+ implements {
+ Efl.Object.constructor;
+ Efl.Object.destructor;
+ Efl.Model.properties { get; }
+ Efl.Model.property_set;
+ Efl.Model.property_get;
+ Efl.Model.child_add;
+ Efl.Model.child_del;
+ Efl.Model.children_slice_get;
+ Efl.Model.children_count_get;
+ }
+}
diff --git a/src/lib/efl/Efl.h b/src/lib/efl/Efl.h
index 0aac8377e5..147596828d 100644
--- a/src/lib/efl/Efl.h
+++ b/src/lib/efl/Efl.h
@@ -120,6 +120,11 @@ EAPI extern const Efl_Event_Description _EFL_GFX_PATH_CHANGED;
#include "interfaces/efl_canvas.eo.h"
+#include "interfaces/efl_ui_view.eo.h"
+#include "interfaces/efl_ui_model_connect.eo.h"
+#include "interfaces/efl_ui_factory.eo.h"
+#include "interfaces/efl_ui_model_factory_connect.eo.h"
+
/* Packing & containers */
#include "interfaces/efl_container.eo.h"
#include "interfaces/efl_pack.eo.h"
diff --git a/src/lib/efl/Efl_Model_Common.h b/src/lib/efl/Efl_Model_Common.h
index 68de92a0a1..6a8c94a757 100644
--- a/src/lib/efl/Efl_Model_Common.h
+++ b/src/lib/efl/Efl_Model_Common.h
@@ -10,6 +10,7 @@ EAPI extern Eina_Error EFL_MODEL_ERROR_READ_ONLY;
EAPI extern Eina_Error EFL_MODEL_ERROR_INIT_FAILED;
EAPI extern Eina_Error EFL_MODEL_ERROR_INCORRECT_VALUE;
EAPI extern Eina_Error EFL_MODEL_ERROR_PERMISSION_DENIED;
+EAPI extern Eina_Error EFL_MODEL_ERROR_INVALID_OBJECT;
/**
* @struct _Efl_Model_Children_Event
diff --git a/src/lib/efl/interfaces/efl_interfaces_main.c b/src/lib/efl/interfaces/efl_interfaces_main.c
index 4251ea3fe5..adde8b5082 100644
--- a/src/lib/efl/interfaces/efl_interfaces_main.c
+++ b/src/lib/efl/interfaces/efl_interfaces_main.c
@@ -55,6 +55,10 @@ EAPI const Efl_Event_Description _EFL_GFX_PATH_CHANGED =
#include "interfaces/efl_ui_progress.eo.c"
#include "interfaces/efl_ui_menu.eo.c"
#include "interfaces/efl_ui_item.eo.c"
+#include "interfaces/efl_ui_view.eo.c"
+#include "interfaces/efl_ui_model_connect.eo.c"
+#include "interfaces/efl_ui_factory.eo.c"
+#include "interfaces/efl_ui_model_factory_connect.eo.c"
EAPI void
__efl_internal_init(void)
diff --git a/src/lib/efl/interfaces/efl_model_common.c b/src/lib/efl/interfaces/efl_model_common.c
index afe6a040ce..07134d8bff 100644
--- a/src/lib/efl/interfaces/efl_model_common.c
+++ b/src/lib/efl/interfaces/efl_model_common.c
@@ -12,6 +12,7 @@ EAPI Eina_Error EFL_MODEL_ERROR_READ_ONLY = 0;
EAPI Eina_Error EFL_MODEL_ERROR_INIT_FAILED = 0;
EAPI Eina_Error EFL_MODEL_ERROR_PERMISSION_DENIED = 0;
EAPI Eina_Error EFL_MODEL_ERROR_INCORRECT_VALUE = 0;
+EAPI Eina_Error EFL_MODEL_ERROR_INVALID_OBJECT = 0;
static const char EFL_MODEL_ERROR_UNKNOWN_STR[] = "Unknown Error";
static const char EFL_MODEL_ERROR_NOT_SUPPORTED_STR[] = "Operation not supported";
@@ -20,6 +21,8 @@ static const char EFL_MODEL_ERROR_READ_ONLY_STR[] = "Value read only";
static const char EFL_MODEL_ERROR_INIT_FAILED_STR[] = "Init failed";
static const char EFL_MODEL_ERROR_PERMISSION_DENIED_STR[] = "Permission denied";
static const char EFL_MODEL_ERROR_INCORRECT_VALUE_STR[] = "Incorrect value";
+static const char EFL_MODEL_ERROR_INVALID_OBJECT_STR[] = "Object is invalid";
+
EAPI int
efl_model_init(void)
@@ -45,6 +48,9 @@ efl_model_init(void)
EFL_MODEL_ERROR_PERMISSION_DENIED = eina_error_msg_static_register(
EFL_MODEL_ERROR_PERMISSION_DENIED_STR);
+ EFL_MODEL_ERROR_INVALID_OBJECT = eina_error_msg_static_register(
+ EFL_MODEL_ERROR_INVALID_OBJECT_STR);
+
return EINA_TRUE;
}
diff --git a/src/lib/efl/interfaces/efl_ui_factory.eo b/src/lib/efl/interfaces/efl_ui_factory.eo
new file mode 100644
index 0000000000..fc3e84baff
--- /dev/null
+++ b/src/lib/efl/interfaces/efl_ui_factory.eo
@@ -0,0 +1,19 @@
+interface Efl.Ui.Factory (Efl.Ui.Model.Connect)
+{
+ methods {
+ create {
+ [[Create a UI object from the necessary properties in the specified model.]]
+ params {
+ model: Efl.Model;
+ parent: Efl.Canvas;
+ }
+ return: Efl.Canvas;
+ }
+ release {
+ [[Release a UI object and disconnec from models.]]
+ params {
+ ui_view: Efl.Canvas;
+ }
+ }
+ }
+}
diff --git a/src/lib/efl/interfaces/efl_ui_model_connect.eo b/src/lib/efl/interfaces/efl_ui_model_connect.eo
new file mode 100644
index 0000000000..42eb89e721
--- /dev/null
+++ b/src/lib/efl/interfaces/efl_ui_model_connect.eo
@@ -0,0 +1,11 @@
+interface Efl.Ui.Model.Connect
+{
+ methods {
+ connect {
+ params {
+ name: string;
+ property: string;
+ }
+ }
+ }
+}
diff --git a/src/lib/efl/interfaces/efl_ui_model_factory_connect.eo b/src/lib/efl/interfaces/efl_ui_model_factory_connect.eo
new file mode 100644
index 0000000000..1330e5ad37
--- /dev/null
+++ b/src/lib/efl/interfaces/efl_ui_model_factory_connect.eo
@@ -0,0 +1,11 @@
+interface Efl.Ui.Model.Factory.Connect
+{
+ methods {
+ connect {
+ params {
+ name: string;
+ factory: Efl.Ui.Factory;
+ }
+ }
+ }
+}
diff --git a/src/lib/efl/interfaces/efl_ui_view.eo b/src/lib/efl/interfaces/efl_ui_view.eo
new file mode 100644
index 0000000000..e5957ee445
--- /dev/null
+++ b/src/lib/efl/interfaces/efl_ui_view.eo
@@ -0,0 +1,12 @@
+interface Efl.Ui.View ()
+{
+ methods {
+ @property model {
+ [[Model that is/will be ]]
+ get {} set {}
+ values {
+ model: Efl.Model;
+ }
+ }
+ }
+}
diff --git a/src/lib/elementary/Elementary.h b/src/lib/elementary/Elementary.h
index 8d6bb34b91..d917a572c0 100644
--- a/src/lib/elementary/Elementary.h
+++ b/src/lib/elementary/Elementary.h
@@ -265,6 +265,7 @@ EAPI extern Elm_Version *elm_version;
# include <efl_ui_text.eo.h>
# include <efl_ui_text_editable.eo.h>
# include <efl_ui_clock.eo.h>
+# include <efl_ui_image_factory.eo.h>
#endif
/* include deprecated calls last of all */
diff --git a/src/lib/elementary/efl_ui_image.c b/src/lib/elementary/efl_ui_image.c
index 1fecc682e4..0576fbb760 100644
--- a/src/lib/elementary/efl_ui_image.c
+++ b/src/lib/elementary/efl_ui_image.c
@@ -47,6 +47,8 @@ static const Evas_Smart_Cb_Description _smart_callbacks[] = {
static Eina_Bool _key_action_activate(Evas_Object *obj, const char *params);
static Eina_Bool _efl_ui_image_smart_internal_file_set(Eo *obj, Efl_Ui_Image_Data *sd, const char *file, const Eina_File *f, const char *key);
static void _efl_ui_image_remote_copier_cancel(Eo *obj, Efl_Ui_Image_Data *sd);
+void _efl_ui_image_sizing_eval(Evas_Object *obj);
+static void _efl_ui_image_model_properties_changed_cb(void *data, const Efl_Event *event);
static const Elm_Action key_actions[] = {
{"activate", _key_action_activate},
@@ -566,6 +568,21 @@ _efl_ui_image_efl_canvas_group_group_del(Eo *obj, Efl_Ui_Image_Data *sd)
if (sd->remote.copier) _efl_ui_image_remote_copier_cancel(obj, sd);
if (sd->remote.binbuf) ELM_SAFE_FREE(sd->remote.binbuf, eina_binbuf_free);
ELM_SAFE_FREE(sd->remote.key, eina_stringshare_del);
+
+ if (sd->pfuture)
+ {
+ efl_future_cancel(sd->pfuture);
+ sd->pfuture = NULL;
+ }
+
+ if (sd->model)
+ {
+ efl_event_callback_del(sd->model, EFL_MODEL_EVENT_PROPERTIES_CHANGED,
+ _efl_ui_image_model_properties_changed_cb, obj);
+ efl_unref(sd->model);
+ sd->model = NULL;
+ }
+
efl_canvas_group_del(efl_super(obj, MY_CLASS));
}
@@ -1724,6 +1741,187 @@ _efl_ui_image_icon_get(Eo *obj EINA_UNUSED, Efl_Ui_Image_Data *sd)
return sd->stdicon;
}
+static void
+_prop_future_error_cb(void* data, Efl_Event const* event EINA_UNUSED)
+{
+ Eo *obj = data;
+ EFL_UI_IMAGE_DATA_GET(obj, pd);
+ pd->pfuture = NULL;
+}
+
+static void
+_prop_key_future_then_cb(void* data, Efl_Event const * event)
+{
+ Eo *obj = data;
+ Eina_Accessor *acc = (Eina_Accessor *)((Efl_Future_Event_Success*)event->info)->value;
+ Eina_Value *value;
+ char *filename, *key;
+
+ EFL_UI_IMAGE_DATA_GET(obj, pd);
+ pd->pfuture = NULL;
+
+ if (eina_accessor_data_get(acc, 0, (void **)&value) && value)
+ {
+ filename = eina_value_to_string(value);
+ }
+ else return;
+
+ if (eina_accessor_data_get(acc, 1, (void **)&value) && value)
+ {
+ key = eina_value_to_string(value);
+ }
+ else
+ {
+ free(filename);
+ return;
+ }
+
+ elm_image_file_set(obj, filename, key);
+ free(filename);
+ free(key);
+}
+
+static void
+_prop_future_then_cb(void* data, Efl_Event const * event)
+{
+ Eo *obj = data;
+ Eina_Value *value = (Eina_Value*)((Efl_Future_Event_Success*)event->info)->value;
+ char *text;
+ EFL_UI_IMAGE_DATA_GET(obj, pd);
+ pd->pfuture = NULL;
+
+ const Eina_Value_Type *vtype = eina_value_type_get(value);
+
+ if (vtype == EINA_VALUE_TYPE_STRING || vtype == EINA_VALUE_TYPE_STRINGSHARE)
+ {
+ eina_value_get(value, &text);
+ if (pd->con_icon) efl_ui_image_icon_set(obj, text);
+ else elm_image_file_set(obj, text, NULL);
+ }
+ else
+ {
+ text = eina_value_to_string(value);
+ if (pd->con_icon) efl_ui_image_icon_set(obj, text);
+ else elm_image_file_set(obj, text, NULL);
+ free(text);
+ }
+}
+
+void
+_update_viewmodel(Eo *obj, Efl_Ui_Image_Data *pd)
+{
+ if (pd->model && pd->prop_con)
+ {
+ if (pd->pfuture) efl_future_cancel(pd->pfuture);
+
+ pd->pfuture = efl_model_property_get(pd->model, pd->prop_con);
+
+ if (pd->prop_key)
+ {
+ const Eina_Array *properties;
+ Eina_Array_Iterator it;
+ char *property;
+ unsigned int i = 0;
+
+ properties = efl_model_properties_get(pd->model);
+ EINA_ARRAY_ITER_NEXT(properties, i, property, it)
+ {
+ if (strcmp(property, pd->prop_key) == 0)
+ {
+ Efl_Future *futures[2] = {NULL,};
+ futures[0] = pd->pfuture;
+ futures[1] = efl_model_property_get(pd->model, pd->prop_key);
+ pd->pfuture = efl_future_all(futures[0], futures[1]);
+ efl_future_then(pd->pfuture, &_prop_key_future_then_cb,
+ &_prop_future_error_cb, NULL, obj);
+ return;
+ }
+ }
+ }
+
+ efl_future_then(pd->pfuture, &_prop_future_then_cb,
+ &_prop_future_error_cb, NULL, obj);
+ }
+}
+
+static void
+_efl_ui_image_model_properties_changed_cb(void *data, const Efl_Event *event)
+{
+ Efl_Model_Property_Event *evt = event->info;
+ Eo *obj = data;
+ EFL_UI_IMAGE_DATA_GET(obj, pd);
+
+ if (!evt->changed_properties)
+ return;
+
+ if (pd->model && pd->prop_con)
+ {
+ Eina_Array_Iterator it;
+ const char *prop;
+ unsigned int i;
+
+ EINA_ARRAY_ITER_NEXT(evt->changed_properties, i, prop, it)
+ {
+ if (!strcmp(pd->prop_con, prop) || (pd->prop_key && !strcmp(pd->prop_key, prop)))
+ {
+ _update_viewmodel(obj, pd);
+ return;
+ }
+ }
+ }
+}
+
+EOLIAN static void
+_efl_ui_image_efl_ui_view_model_set(Eo *obj, Efl_Ui_Image_Data *pd, Efl_Model *model)
+{
+ if (pd->model)
+ {
+ efl_event_callback_del(pd->model, EFL_MODEL_EVENT_PROPERTIES_CHANGED,
+ _efl_ui_image_model_properties_changed_cb, obj);
+ efl_unref(pd->model);
+ pd->model = NULL;
+ }
+
+ if (model)
+ {
+ pd->model = model;
+ efl_ref(pd->model);
+ efl_event_callback_add(pd->model, EFL_MODEL_EVENT_PROPERTIES_CHANGED,
+ _efl_ui_image_model_properties_changed_cb, obj);
+ }
+
+ _update_viewmodel(obj, pd);
+}
+
+EOLIAN static Efl_Model *
+_efl_ui_image_efl_ui_view_model_get(Eo *obj EINA_UNUSED, Efl_Ui_Image_Data *pd)
+{
+ return pd->model;
+}
+
+EOLIAN static void
+_efl_ui_image_efl_ui_model_connect_connect(Eo *obj, Efl_Ui_Image_Data *pd, const char *name, const char *property)
+{
+ if (strcmp(name, "filename") == 0)
+ {
+ pd->con_icon = EINA_FALSE;
+ eina_stringshare_replace(&pd->prop_con, property);
+ }
+ else if (strcmp(name, "icon") == 0)
+ {
+ pd->con_icon = EINA_TRUE;
+ eina_stringshare_replace(&pd->prop_con, property);
+ eina_stringshare_replace(&pd->prop_key, NULL);
+ }
+ else if (strcmp(name, "key") == 0)
+ {
+ eina_stringshare_replace(&pd->prop_key, property);
+ }
+ else return;
+
+ _update_viewmodel(obj, pd);
+}
+
EAPI void
elm_image_smooth_set(Evas_Object *obj, Eina_Bool smooth)
{
diff --git a/src/lib/elementary/efl_ui_image.eo b/src/lib/elementary/efl_ui_image.eo
index 4bc05cbb71..d559f850fc 100644
--- a/src/lib/elementary/efl_ui_image.eo
+++ b/src/lib/elementary/efl_ui_image.eo
@@ -45,7 +45,8 @@ struct Efl.Ui.Image.Error
class Efl.Ui.Image (Elm.Widget, Efl.Ui.Clickable, Efl.Ui.Draggable,
Efl.File, Efl.Image, Efl.Image.Load, Efl.Player, Efl.Gfx.View,
Elm.Interface.Atspi_Image, Elm.Interface.Atspi_Widget_Action,
- Edje.Object, Efl.Orientation, Efl.Flipable)
+ Edje.Object, Efl.Orientation, Efl.Flipable,
+ Efl.Ui.View, Efl.Ui.Model.Connect)
{
[[ Efl UI image class]]
event_prefix: efl_ui_image;
@@ -143,6 +144,8 @@ class Efl.Ui.Image (Elm.Widget, Efl.Ui.Clickable, Efl.Ui.Draggable,
Efl.Canvas.Group.group_del;
Efl.Canvas.Group.group_member_add;
Efl.Ui.Draggable.drag_target { get; set; }
+ Efl.Ui.Model.Connect.connect;
+ Efl.Ui.View.model { get; set; }
Elm.Widget.theme_apply;
Elm.Widget.widget_event;
Elm.Interface.Atspi_Image.extents { get; }
diff --git a/src/lib/elementary/efl_ui_image_factory.c b/src/lib/elementary/efl_ui_image_factory.c
new file mode 100644
index 0000000000..a07d0e4f67
--- /dev/null
+++ b/src/lib/elementary/efl_ui_image_factory.c
@@ -0,0 +1,59 @@
+#ifdef HAVE_CONFIG_H
+# include "elementary_config.h"
+#endif
+
+#include <Elementary.h>
+#include "elm_priv.h"
+
+#define MY_CLASS EFL_UI_IMAGE_FACTORY_CLASS
+#define MY_CLASS_NAME "Efl.Ui.Image_Factory"
+
+typedef struct _Efl_Ui_Image_Factory_Data
+{
+ Eina_Stringshare *property;
+} Efl_Ui_Image_Factory_Data;
+
+EOLIAN static Eo *
+_efl_ui_image_factory_efl_object_constructor(Eo *obj, Efl_Ui_Image_Factory_Data *pd)
+{
+ obj = efl_constructor(efl_super(obj, MY_CLASS));
+
+ pd->property = NULL;
+
+ return obj;
+}
+
+EOLIAN static void
+_efl_ui_image_factory_efl_object_destructor(Eo *obj EINA_UNUSED, Efl_Ui_Image_Factory_Data *pd)
+{
+ eina_stringshare_del(pd->property);
+ pd->property = NULL;
+
+ efl_destructor(efl_super(obj, MY_CLASS));
+}
+
+EOLIAN static Efl_Canvas *
+_efl_ui_image_factory_efl_ui_factory_create(Eo *obj EINA_UNUSED, Efl_Ui_Image_Factory_Data *pd, Efl_Model *model, Efl_Canvas *parent)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(pd->property, NULL);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(parent, NULL);
+ Efl_Canvas *ui_view = efl_add(EFL_UI_IMAGE_CLASS, parent);
+ efl_ui_view_model_set(ui_view, model);
+ efl_ui_model_connect(ui_view, "filename", pd->property);
+
+ return ui_view;
+}
+
+EOLIAN static void
+_efl_ui_image_factory_efl_ui_factory_release(Eo *obj EINA_UNUSED, Efl_Ui_Image_Factory_Data *pd EINA_UNUSED, Efl_Canvas *ui_view)
+{
+ efl_parent_set(ui_view, NULL);
+}
+
+EOLIAN static void
+_efl_ui_image_factory_efl_ui_model_connect_connect(Eo *obj EINA_UNUSED, Efl_Ui_Image_Factory_Data *pd, const char *name EINA_UNUSED, const char *property)
+{
+ eina_stringshare_replace(&pd->property, property);
+}
+
+#include "efl_ui_image_factory.eo.c"
diff --git a/src/lib/elementary/efl_ui_image_factory.eo b/src/lib/elementary/efl_ui_image_factory.eo
new file mode 100644
index 0000000000..bfc5c8abb7
--- /dev/null
+++ b/src/lib/elementary/efl_ui_image_factory.eo
@@ -0,0 +1,10 @@
+class Efl.Ui.Image.Factory (Efl.Object, Efl.Ui.Factory)
+{
+ implements {
+ Efl.Object.constructor;
+ Efl.Object.destructor;
+ Efl.Ui.Factory.create;
+ Efl.Ui.Factory.release;
+ Efl.Ui.Model.Connect.connect;
+ }
+}
diff --git a/src/lib/elementary/efl_ui_widget_image.h b/src/lib/elementary/efl_ui_widget_image.h
index 2afd87fab9..f1480f09e8 100644
--- a/src/lib/elementary/efl_ui_widget_image.h
+++ b/src/lib/elementary/efl_ui_widget_image.h
@@ -80,6 +80,10 @@ struct _Efl_Ui_Image_Data
const char *stdicon;
+ Efl_Model *model;
+ Efl_Future *pfuture;
+ Eina_Stringshare *prop_con;
+ Eina_Stringshare *prop_key;
struct {
int requested_size;
@@ -98,6 +102,7 @@ struct _Efl_Ui_Image_Data
Eina_Bool async_enable : 1;
Eina_Bool scale_up : 1;
Eina_Bool scale_down : 1;
+ Eina_Bool con_icon : 1;
};
/**
diff --git a/src/lib/elementary/elm_layout.c b/src/lib/elementary/elm_layout.c
index b5d2f56cb8..01311fa5f6 100644
--- a/src/lib/elementary/elm_layout.c
+++ b/src/lib/elementary/elm_layout.c
@@ -22,11 +22,14 @@
#define MY_CLASS_NAME_LEGACY "elm_layout"
Eo *_elm_layout_pack_proxy_get(Elm_Layout *obj, Edje_Part_Type type, const char *part);
+static void _efl_model_properties_changed_cb(void *, const Efl_Event *);
static const char SIG_THEME_CHANGED[] = "theme,changed";
const char SIG_LAYOUT_FOCUSED[] = "focused";
const char SIG_LAYOUT_UNFOCUSED[] = "unfocused";
+const char SIGNAL_PREFIX[] = "signal/";
+
/* smart callbacks coming from elm layout objects: */
static const Evas_Smart_Cb_Description _smart_callbacks[] = {
{SIG_THEME_CHANGED, ""},
@@ -106,6 +109,13 @@ struct _Elm_Layout_Sub_Object_Cursor
Eina_Bool engine_only : 1;
};
+typedef struct _Elm_Layout_Sub_Property_Future Elm_Layout_Sub_Property_Future;
+struct _Elm_Layout_Sub_Property_Future
+{
+ Elm_Layout_Smart_Data *pd;
+ Eina_Array *name_arr;
+};
+
static void
_on_sub_object_size_hint_change(void *data,
Evas *e EINA_UNUSED,
@@ -793,6 +803,17 @@ _elm_layout_efl_canvas_group_group_del(Eo *obj, Elm_Layout_Smart_Data *sd)
free(esd);
}
+ if(sd->model)
+ {
+ efl_event_callback_del(sd->model, EFL_MODEL_EVENT_PROPERTIES_CHANGED, _efl_model_properties_changed_cb, sd);
+ efl_unref(sd->model);
+ sd->model = NULL;
+ }
+ eina_hash_free(sd->prop_connect);
+ sd->prop_connect = NULL;
+ eina_hash_free(sd->factories);
+ sd->factories = NULL;
+
eina_stringshare_del(sd->klass);
eina_stringshare_del(sd->group);
@@ -1323,6 +1344,20 @@ _elm_layout_text_set(Eo *obj, Elm_Layout_Smart_Data *sd, const char *part, const
sub_d->obj = _elm_access_edje_object_part_object_register
(obj, elm_layout_edje_get(obj), part);
+ if (sd->model && !sd->view_updated)
+ {
+ Eina_Stringshare *prop = eina_hash_find(sd->prop_connect, sub_d->part);
+ if (prop)
+ {
+ Eina_Value v;
+ eina_value_setup(&v, EINA_VALUE_TYPE_STRING);
+ eina_value_set(&v, text);
+ efl_model_property_set(sd->model, prop, &v);
+ eina_value_flush(&v);
+ }
+ }
+
+ sd->view_updated = EINA_FALSE;
return EINA_TRUE;
}
@@ -1896,6 +1931,291 @@ _elm_layout_efl_object_dbg_info_get(Eo *eo_obj, Elm_Layout_Smart_Data *_pd EINA_
}
}
+static void
+_prop_future_error_cb(void* data, Efl_Event const*event EINA_UNUSED)
+{
+ Elm_Layout_Sub_Property_Future *sub_pp = data;
+ Eina_Array_Iterator iterator;
+ Eina_Stringshare *name;
+ unsigned int i = 0;
+
+ EINA_ARRAY_ITER_NEXT(sub_pp->name_arr, i, name, iterator)
+ eina_stringshare_del(name);
+
+ eina_array_free(sub_pp->name_arr);
+ free(sub_pp);
+}
+
+static void
+_view_update(Elm_Layout_Smart_Data *pd, const char *name, const char *property)
+{
+ const char *source;
+ Eina_Strbuf *buf;
+
+ if (strncmp(SIGNAL_PREFIX, name, sizeof(SIGNAL_PREFIX) -1) != 0)
+ {
+ elm_layout_text_set(pd->obj, name, property);
+ return;
+ }
+
+ ELM_WIDGET_DATA_GET_OR_RETURN(pd->obj, wd);
+ source = efl_class_name_get(efl_class_get(pd->model));
+
+ buf = eina_strbuf_new();
+ eina_strbuf_append(buf, name);
+ eina_strbuf_remove(buf, 0, sizeof(SIGNAL_PREFIX)-1);
+ eina_strbuf_replace_all(buf, "%v", property);
+
+ edje_object_signal_emit(wd->resize_obj, eina_strbuf_string_get(buf), source);
+ eina_strbuf_free(buf);
+}
+
+static void
+_prop_future_then_cb(void* data, Efl_Event const*event)
+{
+ Elm_Layout_Sub_Property_Future *sub_pp = data;
+ Elm_Layout_Smart_Data *pd = sub_pp->pd;
+ Eina_Accessor *value_acc = (Eina_Accessor *)((Efl_Future_Event_Success*)event->info)->value;
+ Eina_Value *value;
+ Eina_Stringshare *name;
+ char *text;
+ unsigned int i = 0;
+ unsigned int acc_i = 0;
+
+ while (eina_accessor_data_get(value_acc, acc_i, (void **)&value))
+ {
+ const Eina_Value_Type *vtype = eina_value_type_get(value);
+ name = eina_array_data_get(sub_pp->name_arr, i);
+
+ pd->view_updated = EINA_TRUE;
+ if (vtype == EINA_VALUE_TYPE_STRING || vtype == EINA_VALUE_TYPE_STRINGSHARE)
+ {
+ eina_value_get(value, &text);
+ _view_update(pd, name, text);
+ }
+ else
+ {
+ text = eina_value_to_string(value);
+ _view_update(pd, name, text);
+ free(text);
+ }
+ eina_stringshare_del(name);
+ ++acc_i;
+ }
+ eina_array_free(sub_pp->name_arr);
+ free(sub_pp);
+}
+
+static void
+_elm_layout_view_model_update(Elm_Layout_Smart_Data *pd)
+{
+ Elm_Layout_Sub_Property_Future *sub_pp;
+ Efl_Future **future_arr, **f, *future_all;
+ Eina_Hash_Tuple *tuple;
+ Eina_Iterator *it_p;
+ int size;
+
+ if (!pd->prop_connect) return;
+
+ size = eina_hash_population(pd->prop_connect);
+ if (size == 0) return;
+
+ future_arr = alloca((size + 1) * sizeof(Efl_Future*));
+ f = future_arr;
+
+ sub_pp = ELM_NEW(Elm_Layout_Sub_Property_Future);
+ sub_pp->pd = pd;
+ sub_pp->name_arr = eina_array_new(size);
+
+ it_p = eina_hash_iterator_tuple_new(pd->prop_connect);
+ while (eina_iterator_next(it_p, (void **)&tuple))
+ {
+ *f = efl_model_property_get(pd->model, tuple->data);
+ eina_array_push(sub_pp->name_arr, eina_stringshare_ref(tuple->key));
+ f++;
+ }
+ eina_iterator_free(it_p);
+ *f = NULL;
+
+ future_all = efl_future_iterator_all(eina_carray_iterator_new((void**)future_arr));
+
+ efl_future_then(future_all, &_prop_future_then_cb, &_prop_future_error_cb, NULL, sub_pp);
+}
+
+static void
+_efl_model_properties_changed_cb(void *data, const Efl_Event *event)
+{
+ Elm_Layout_Smart_Data *pd = data;
+ Efl_Model_Property_Event *evt = event->info;
+ Eina_Stringshare *ss_prop;
+ Eina_Hash_Tuple *tuple;
+ Eina_Array *names, *futures;
+ Eina_Iterator *it_p;
+ const char *prop;
+ Eina_Array_Iterator it;
+ unsigned int i;
+
+ if (!evt->changed_properties || !pd->prop_connect) return;
+
+ names = eina_array_new(1);
+ futures = eina_array_new(1);
+
+ EINA_ARRAY_ITER_NEXT(evt->changed_properties, i, prop, it)
+ {
+ ss_prop = eina_stringshare_add(prop);
+ it_p = eina_hash_iterator_tuple_new(pd->prop_connect);
+ while (eina_iterator_next(it_p, (void **)&tuple))
+ {
+ if (tuple->data == ss_prop)
+ {
+ eina_array_push(names, eina_stringshare_ref(tuple->key));
+ eina_array_push(futures, efl_model_property_get(pd->model, prop));
+ }
+ }
+ eina_iterator_free(it_p);
+ eina_stringshare_del(ss_prop);
+ }
+
+ if (eina_array_count(names))
+ {
+ Elm_Layout_Sub_Property_Future *sub_pp;
+ Efl_Future *future_all;
+
+ sub_pp = ELM_NEW(Elm_Layout_Sub_Property_Future);
+ sub_pp->pd = pd;
+ sub_pp->name_arr = names;
+
+ future_all = efl_future_iterator_all(eina_array_iterator_new(futures));
+ efl_future_then(future_all, &_prop_future_then_cb, &_prop_future_error_cb, NULL, sub_pp);
+ }
+ else
+ eina_array_free(names);
+
+ eina_array_free(futures);
+}
+
+EOLIAN static void
+_elm_layout_efl_ui_view_model_set(Eo *obj EINA_UNUSED, Elm_Layout_Smart_Data *pd, Efl_Model *model)
+{
+ if (pd->model)
+ {
+ efl_event_callback_del(pd->model, EFL_MODEL_EVENT_PROPERTIES_CHANGED, _efl_model_properties_changed_cb, pd);
+ efl_unref(pd->model);
+ pd->model = NULL;
+ }
+
+ if (model)
+ {
+ pd->model = model;
+ efl_ref(pd->model);
+ efl_event_callback_add(pd->model, EFL_MODEL_EVENT_PROPERTIES_CHANGED, _efl_model_properties_changed_cb, pd);
+ }
+
+ if (pd->prop_connect)
+ _elm_layout_view_model_update(pd);
+
+ if (pd->factories)
+ {
+ Eina_Hash_Tuple *tuple;
+ Eina_Stringshare *name;
+ Efl_Ui_Factory *factory;
+ Efl_Canvas *content;
+
+ Eina_Iterator *it_p = eina_hash_iterator_tuple_new(pd->factories);
+ while (eina_iterator_next(it_p, (void **)&tuple))
+ {
+ name = tuple->key;
+ factory = tuple->data;
+ content = elm_layout_content_get(pd->obj, name);
+
+ if (content && efl_isa(content, EFL_UI_VIEW_INTERFACE))
+ {
+ efl_ui_view_model_set(content, pd->model);
+ }
+ else
+ {
+ efl_ui_factory_release(factory, content);
+ content = efl_ui_factory_create(factory, pd->model, pd->obj);
+ elm_layout_content_set(pd->obj, name, content);
+ }
+ }
+ eina_iterator_free(it_p);
+ }
+}
+
+EOLIAN static Efl_Model *
+_elm_layout_efl_ui_view_model_get(Eo *obj EINA_UNUSED, Elm_Layout_Smart_Data *pd)
+{
+ return pd->model;
+}
+
+EOLIAN static void
+_elm_layout_efl_ui_model_connect_connect(Eo *obj EINA_UNUSED, Elm_Layout_Smart_Data *pd, const char *name, const char *property)
+{
+ EINA_SAFETY_ON_NULL_RETURN(name);
+ Eina_Stringshare *ss_name, *ss_prop;
+
+ if (!_elm_layout_part_aliasing_eval(obj, pd, &name, EINA_TRUE))
+ return;
+
+ ss_name = eina_stringshare_add(name);
+ ss_prop = eina_stringshare_add(property);
+ if (!pd->prop_connect)
+ {
+ pd->prop_connect = eina_hash_stringshared_new(EINA_FREE_CB(eina_stringshare_del));
+ }
+
+ eina_stringshare_del(eina_hash_set(pd->prop_connect, ss_name, ss_prop));
+
+ if (pd->model)
+ {
+ Elm_Layout_Sub_Property_Future *sub_pp = ELM_NEW(Elm_Layout_Sub_Property_Future);
+ Efl_Future *futures[2] = {NULL,};
+ Efl_Future *future_all = NULL;
+
+ sub_pp->pd = pd;
+ sub_pp->name_arr = eina_array_new(1);
+ eina_array_push(sub_pp->name_arr, eina_stringshare_ref(ss_name));
+ futures[0] = efl_model_property_get(pd->model, ss_prop);
+
+ future_all = efl_future_iterator_all(eina_carray_iterator_new((void**)futures));
+ efl_future_then(future_all, &_prop_future_then_cb, &_prop_future_error_cb, NULL, sub_pp);
+ }
+}
+
+
+EOLIAN static void
+_elm_layout_efl_ui_model_factory_connect_connect(Eo *obj EINA_UNUSED, Elm_Layout_Smart_Data *pd,
+ const char *name, Efl_Ui_Factory *factory)
+{
+ EINA_SAFETY_ON_NULL_RETURN(name);
+ Eina_Stringshare *ss_name;
+ Efl_Ui_Factory *old_factory;
+ Evas_Object *new_ev, *old_ev;
+
+ if (!_elm_layout_part_aliasing_eval(obj, pd, &name, EINA_TRUE))
+ return;
+
+ ss_name = eina_stringshare_add(name);
+
+ if (!pd->factories)
+ pd->factories = eina_hash_stringshared_new(EINA_FREE_CB(efl_unref));
+
+ new_ev = efl_ui_factory_create(factory, pd->model, obj);
+ EINA_SAFETY_ON_NULL_RETURN(new_ev);
+
+ old_factory = eina_hash_set(pd->factories, ss_name, efl_ref(factory));
+ if (old_factory)
+ {
+ old_ev = elm_layout_content_get(obj, name);
+ if (old_ev)
+ efl_ui_factory_release(old_factory, old_ev);
+ efl_unref(old_factory);
+ }
+
+ elm_layout_content_set(obj, name, new_ev);
+}
+
EAPI Evas_Object *
elm_layout_add(Evas_Object *parent)
{
diff --git a/src/lib/elementary/elm_layout.eo b/src/lib/elementary/elm_layout.eo
index 37f1ad17a9..802f567050 100644
--- a/src/lib/elementary/elm_layout.eo
+++ b/src/lib/elementary/elm_layout.eo
@@ -17,7 +17,8 @@ struct Elm.Layout_Part_Alias_Description
real_part: string; [[Target part name for the alias set on Elm.Layout_Part_Proxies_Description::real_part. An example of usage would be "default" on that field, with "elm.content.swallow" on this one]]
}
-class Elm.Layout (Elm.Widget, Efl.Part, Efl.Container, Efl.File)
+class Elm.Layout (Elm.Widget, Efl.Part, Efl.Container, Efl.File,
+ Efl.Ui.View, Efl.Ui.Model.Connect, Efl.Ui.Model.Factory.Connect)
{
[[Elementary layout class]]
legacy_prefix: elm_layout;
@@ -355,6 +356,9 @@ class Elm.Layout (Elm.Widget, Efl.Part, Efl.Container, Efl.File)
Efl.Container.content { get; set; }
Efl.Container.content_unset;
Efl.Part.part;
+ Efl.Ui.View.model { get; set; }
+ Efl.Ui.Model.Connect.connect;
+ Efl.Ui.Model.Factory.Connect.connect;
}
events {
theme,changed; [[Called when theme changed]]
diff --git a/src/lib/elementary/elm_widget_layout.h b/src/lib/elementary/elm_widget_layout.h
index b4a2ed5384..684a11906a 100644
--- a/src/lib/elementary/elm_widget_layout.h
+++ b/src/lib/elementary/elm_widget_layout.h
@@ -53,6 +53,9 @@ typedef struct _Elm_Layout_Smart_Data
Eina_List *subs; /**< List of Elm_Layout_Sub_Object_Data structs, to hold the actual sub objects such as text, content and the children of box and table. */
Eina_List *edje_signals; /**< The list of edje signal callbacks. */
Eina_List *parts_cursors; /**< The list of cursor names of layout parts. This is a list of Elm_Layout_Sub_Object_Cursor struct. */
+ Eina_Hash *prop_connect; /**< The hash of properties connected to layout parts. */
+ Eina_Hash *factories; /**< The hash with parts connected to factories. */
+ Efl_Model *model; /**< The model */
const char *klass; /**< 1st identifier of an edje object group which is used in theme_set. klass and group are used together. */
const char *group; /**< 2nd identifier of an edje object group which is used in theme_set. klass and group are used together. */
int frozen; /**< Layout freeze counter */
@@ -63,6 +66,7 @@ typedef struct _Elm_Layout_Smart_Data
Eina_Bool can_access : 1; /**< This is true when all text(including textblock) parts can be accessible by accessibility. */
Eina_Bool destructed_is : 1; /**< This flag indicates if Elm_Layout destructor was called. This is needed to avoid unnecessary calculation of subobject deletion during layout object's deletion. */
Eina_Bool file_set : 1; /**< This flag indicates if Elm_Layout source is set from a file*/
+ Eina_Bool view_updated : 1; /**< This flag indicates to Elm_Layout don't update model in text_set */
} Elm_Layout_Smart_Data;
/**
diff --git a/src/lib/eo/eina_types.eot b/src/lib/eo/eina_types.eot
index c1d2243b2f..1f97ff4a43 100644
--- a/src/lib/eo/eina_types.eot
+++ b/src/lib/eo/eina_types.eot
@@ -59,3 +59,5 @@ struct @extern Eina.Rw_Slice {
len: size; [[Length of the memory segment]]
mem: void_ptr; [[Pointer to memory segment]]
}
+
+struct @extern Eina.Value.Type;
diff --git a/src/tests/efl/efl_suite.c b/src/tests/efl/efl_suite.c
new file mode 100644
index 0000000000..653aac2201
--- /dev/null
+++ b/src/tests/efl/efl_suite.c
@@ -0,0 +1,51 @@
+/* EINA - EFL data type library
+ * Copyright (C) 2008 Cedric Bail
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;
+ * if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <Eina.h>
+
+#include "efl_suite.h"
+#include "../efl_check.h"
+
+static const Efl_Test_Case etc[] = {
+ { "Efl_Model_Container", efl_test_case_model_container },
+ { NULL, NULL }
+};
+
+int
+main(int argc, char **argv)
+{
+ int failed_count;
+
+ if (!_efl_test_option_disp(argc, argv, etc))
+ return 0;
+
+ putenv("EFL_RUN_IN_TREE=1");
+
+ eina_init();
+
+ failed_count = _efl_suite_build_and_run(argc - 1, (const char **)argv + 1,
+ "Efl", etc);
+
+ eina_shutdown();
+
+ return (failed_count == 0) ? 0 : 255;
+}
diff --git a/src/tests/efl/efl_suite.h b/src/tests/efl/efl_suite.h
new file mode 100644
index 0000000000..d5a7caa9ec
--- /dev/null
+++ b/src/tests/efl/efl_suite.h
@@ -0,0 +1,26 @@
+/* EFL - EFL library
+ * Copyright (C) 2008 Cedric Bail
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;
+ * if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef EFL_SUITE_H_
+#define EFL_SUITE_H_
+
+#include <check.h>
+
+void efl_test_case_model_container(TCase *tc);
+
+#endif /* EFL_SUITE_H_ */
diff --git a/src/tests/efl/efl_test_model_container.c b/src/tests/efl/efl_test_model_container.c
new file mode 100644
index 0000000000..5710ef2337
--- /dev/null
+++ b/src/tests/efl/efl_test_model_container.c
@@ -0,0 +1,171 @@
+/* EFL - EFL library
+ * Copyright (C) 2013 Cedric Bail
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;
+ * if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "efl_suite.h"
+
+#include <Efl.h>
+#include <Ecore.h>
+
+typedef struct _Test_Container_Data {
+ int item_count;
+ Eina_Bool pass_flag;
+ Eina_Bool fail_flag;
+} Test_Container_Data;
+
+typedef struct _Test_Container_Item_Data {
+ Test_Container_Data* test_data;
+ unsigned int index;
+} Test_Container_Item_Data;
+
+const int base_int[7] = {10, 11, 12, 13, 14, 0, 16};
+const char * const base_str[7] = {"A", "B", "C", "D", "E", "", "GH"};
+
+static void
+_future_error_then(void *data EINA_UNUSED, Efl_Event const* event EINA_UNUSED)
+{
+ ck_abort_msg("Promise failed");
+}
+
+static void
+_container_property_get_then(void *data, Efl_Event const *event)
+{
+ Eina_Accessor *value_itt = (Eina_Accessor*)((Efl_Future_Event_Success*)event->info)->value;
+ Test_Container_Item_Data *test_item_data = data;
+ Eina_Value *value_int = NULL;
+ Eina_Value *value_str = NULL;
+ int cmp_int = 0;
+ const char *cmp_str = NULL;
+
+ test_item_data->test_data->item_count++;
+
+ if (!value_itt || !eina_accessor_data_get(value_itt, 0, (void**)&value_int) ||
+ !eina_accessor_data_get(value_itt, 1, (void**)&value_str))
+ {
+ test_item_data->test_data->fail_flag = EINA_TRUE;
+ ecore_main_loop_quit();
+ return;
+ }
+
+ eina_value_get(value_int, &cmp_int);
+ eina_value_get(value_str, &cmp_str);
+
+ if (cmp_int != base_int[test_item_data->index] ||
+ strcmp(cmp_str, base_str[test_item_data->index]) != 0)
+ {
+ test_item_data->test_data->fail_flag = EINA_TRUE;
+ }
+
+ if (test_item_data->test_data->item_count == 7)
+ {
+ test_item_data->test_data->pass_flag = EINA_TRUE;
+ }
+ ecore_main_loop_quit();
+}
+
+static void
+_children_slice_future_then(void *data, Efl_Event const *event)
+{
+ Eina_Accessor *children_accessor = (Eina_Accessor *)((Efl_Future_Event_Success*)event->info)->value;
+ unsigned int i = 0;
+ Efl_Model *child;
+
+ if (children_accessor)
+ {
+ EINA_ACCESSOR_FOREACH(children_accessor, i, child)
+ {
+ Efl_Future *futures[3] = {NULL,};
+ Efl_Future *future_all = NULL;
+ Test_Container_Item_Data *test_item_data = calloc(1, sizeof(Test_Container_Item_Data));
+
+ test_item_data->test_data = data;
+ test_item_data->index = i;
+
+ futures[0] = efl_model_property_get(child, "test_p_int");
+ futures[1] = efl_model_property_get(child, "test_p_str");
+
+ future_all = efl_future_all(futures[0], futures[1]);
+ efl_future_then(future_all, _container_property_get_then, _future_error_then, NULL, test_item_data);
+ }
+ }
+}
+
+
+START_TEST(efl_test_model_container_values)
+{
+ Efl_Model_Container* model;
+ Efl_Future *future;
+ Test_Container_Data test_data;
+ int **cmp_int;
+ const char **cmp_str;
+ int i;
+
+ fail_if(!ecore_init(), "ERROR: Cannot init Ecore!\n");
+ fail_if(!efl_object_init(), "ERROR: Cannot init EO!\n");
+
+ cmp_int = calloc(8, sizeof(int*));
+ cmp_str = calloc(8, sizeof(const char*));
+ for (i = 0; i < 7; ++i)
+ {
+ cmp_int[i] = calloc(1, sizeof(int));
+ *(cmp_int[i]) = base_int[i];
+ cmp_str[i] = strdup(base_str[i]);
+ }
+
+ model = efl_add(EFL_MODEL_CONTAINER_CLASS, NULL);
+
+ efl_model_container_child_property_add(model, "test_p_int", EINA_VALUE_TYPE_INT,
+ eina_carray_iterator_new((void**)cmp_int));
+
+ efl_model_container_child_property_add(model, "test_p_str", EINA_VALUE_TYPE_STRING,
+ eina_carray_iterator_new((void**)cmp_str));
+
+ for (i = 0; i < 7; ++i)
+ {
+ free(cmp_int[i]);
+ free((void*)cmp_str[i]);
+ }
+ free(cmp_int);
+ free(cmp_str);
+
+ future = efl_model_children_slice_get(model, 0, 0);
+
+ test_data.item_count = 0;
+ test_data.pass_flag = EINA_FALSE;
+ test_data.fail_flag = EINA_FALSE;
+
+ efl_future_then(future, _children_slice_future_then, _future_error_then, NULL, &test_data);
+
+ ecore_main_loop_iterate();
+
+ ck_assert(!!test_data.pass_flag);
+ ck_assert(!test_data.fail_flag);
+
+ ecore_shutdown();
+}
+END_TEST
+
+
+void
+efl_test_case_model_container(TCase *tc)
+{
+ tcase_add_test(tc, efl_test_model_container_values);
+}
diff --git a/src/tests/elementary/elm_test_layout.c b/src/tests/elementary/elm_test_layout.c
index b89be351c9..725ab602c4 100644
--- a/src/tests/elementary/elm_test_layout.c
+++ b/src/tests/elementary/elm_test_layout.c
@@ -57,8 +57,44 @@ START_TEST(elm_layout_swallows)
}
END_TEST
+START_TEST(elm_layout_model_connect)
+{
+ char buf[PATH_MAX];
+ Evas_Object *win, *ly;
+ Efl_Model_Item *model;
+ Eina_Value v;
+ const char *part_text;
+ const char text_value[] = "A random string for elm_layout_model_connect test";
+
+ elm_init(1, NULL);
+ win = elm_win_add(NULL, "layout", ELM_WIN_BASIC);
+
+ ly = efl_add(ELM_LAYOUT_CLASS, win);
+ snprintf(buf, sizeof(buf), "%s/objects/test.edj", ELM_TEST_DATA_DIR);
+ elm_layout_file_set(ly, buf, "layout");
+ evas_object_show(ly);
+
+ model = efl_add(EFL_MODEL_ITEM_CLASS, win);
+ ck_assert(!!eina_value_setup(&v, EINA_VALUE_TYPE_STRING));
+ ck_assert(!!eina_value_set(&v, text_value));
+ efl_model_property_set(model, "text_property", &v);
+
+ efl_ui_model_connect(ly, "text", "text_property");
+ efl_ui_view_model_set(ly, model);
+
+ ecore_main_loop_iterate_may_block(EINA_TRUE);
+
+ part_text = elm_layout_text_get(ly, "text");
+
+ ck_assert_str_eq(part_text, text_value);
+
+ elm_shutdown();
+}
+END_TEST
+
void elm_test_layout(TCase *tc)
{
tcase_add_test(tc, elm_atspi_role_get);
tcase_add_test(tc, elm_layout_swallows);
+ tcase_add_test(tc, elm_layout_model_connect);
}