From 05eecf5c8fdceda95649b4ccda7014a76fb0347f Mon Sep 17 00:00:00 2001 From: Larry Jr Date: Sun, 5 Apr 2015 15:19:45 +0200 Subject: [PATCH] emodel: Created Emodel and Eio_Model. --- Makefile.am | 5 +- configure.ac | 12 + pc/.gitignore | 3 + pc/eio-cxx.pc.in | 12 + pc/emodel-cxx.pc.in | 12 + pc/emodel.pc.in | 12 + pkgbuild/PKGBUILD | 2 +- src/Makefile.am | 7 +- src/Makefile_Efl_Cxx.am | 2 +- src/Makefile_Eio.am | 22 +- src/Makefile_Eio_Cxx.am | 22 + src/Makefile_Emodel.am | 78 +++ src/Makefile_Emodel_Cxx.am | 22 + src/examples/eio/Makefile.am | 2 + src/lib/eio/eio_model.c | 774 +++++++++++++++++++++ src/lib/eio/eio_model.eo | 49 ++ src/lib/eio/eio_model.h | 45 ++ src/lib/eio/eio_model_private.h | 62 ++ src/lib/emodel/Emodel.h | 127 ++++ src/lib/emodel/Emodel_Common.h | 106 +++ src/lib/emodel/emodel.c | 6 + src/lib/emodel/emodel.eo | 326 +++++++++ src/tests/emodel/emodel_suite.c | 138 ++++ src/tests/emodel/emodel_test_file.c | 273 ++++++++ src/tests/emodel/emodel_test_monitor_add.c | 105 +++ 25 files changed, 2217 insertions(+), 7 deletions(-) create mode 100644 pc/eio-cxx.pc.in create mode 100644 pc/emodel-cxx.pc.in create mode 100644 pc/emodel.pc.in create mode 100644 src/Makefile_Eio_Cxx.am create mode 100644 src/Makefile_Emodel.am create mode 100644 src/Makefile_Emodel_Cxx.am create mode 100644 src/lib/eio/eio_model.c create mode 100644 src/lib/eio/eio_model.eo create mode 100644 src/lib/eio/eio_model.h create mode 100644 src/lib/eio/eio_model_private.h create mode 100644 src/lib/emodel/Emodel.h create mode 100644 src/lib/emodel/Emodel_Common.h create mode 100644 src/lib/emodel/emodel.c create mode 100644 src/lib/emodel/emodel.eo create mode 100644 src/tests/emodel/emodel_suite.c create mode 100644 src/tests/emodel/emodel_test_file.c create mode 100644 src/tests/emodel/emodel_test_monitor_add.c diff --git a/Makefile.am b/Makefile.am index dee94789e5..14b8572bb1 100644 --- a/Makefile.am +++ b/Makefile.am @@ -143,6 +143,7 @@ pc/ecore-evas.pc \ pc/ecore-avahi.pc \ pc/ector.pc \ pc/embryo.pc \ +pc/emodel.pc \ pc/eio.pc \ pc/eldbus.pc \ pc/efreet.pc \ @@ -162,7 +163,9 @@ pc/ecore-cxx.pc \ pc/eolian-cxx.pc \ pc/edje-cxx.pc \ pc/eet-cxx.pc \ -pc/eo-cxx.pc +pc/eo-cxx.pc \ +pc/emodel-cxx.pc \ +pc/eio-cxx.pc endif if HAVE_ELUA diff --git a/configure.ac b/configure.ac index 9f4b269a6e..da6abf853a 100644 --- a/configure.ac +++ b/configure.ac @@ -3944,6 +3944,14 @@ EFL_EVAL_PKGS([ECORE_EVAS]) EFL_LIB_END([Ecore_Evas]) #### End of Ecore_Evas +#### Emodel +EFL_LIB_START([Emodel]) +EFL_ADD_LIBS([EMODEL], []) +EFL_INTERNAL_DEPEND_PKG([EMODEL], [eo]) +EFL_INTERNAL_DEPEND_PKG([EMODEL], [eina]) +EFL_LIB_END([Emodel]) +#### End of Emodel + #### Eio EFL_LIB_START([Eio]) @@ -3957,6 +3965,7 @@ EFL_LIB_START([Eio]) EFL_PLATFORM_DEPEND([EIO], [evil]) ### Checks for libraries +EFL_INTERNAL_DEPEND_PKG([EIO], [emodel]) EFL_INTERNAL_DEPEND_PKG([EIO], [ecore]) EFL_INTERNAL_DEPEND_PKG([EIO], [eet]) EFL_INTERNAL_DEPEND_PKG([EIO], [eo]) @@ -4534,6 +4543,8 @@ pc/eolian.pc pc/eolian-cxx.pc pc/efl.pc pc/efl-cxx.pc +pc/emodel.pc +pc/emodel-cxx.pc pc/evas-fb.pc pc/evas-opengl-x11.pc pc/evas-opengl-sdl.pc @@ -4573,6 +4584,7 @@ pc/ecore-avahi.pc pc/ector.pc pc/embryo.pc pc/eio.pc +pc/eio-cxx.pc pc/eldbus.pc pc/efreet.pc pc/efreet-mime.pc diff --git a/pc/.gitignore b/pc/.gitignore index 25049d8fa9..447b41789b 100644 --- a/pc/.gitignore +++ b/pc/.gitignore @@ -28,9 +28,12 @@ /eina-cxx.pc /eet-cxx.pc /eio.pc +/eio-cxx.pc /eldbus.pc /elocation.pc /embryo.pc +/emodel.pc +/emodel-cxx.pc /emotion.pc /eo.pc /ephysics.pc diff --git a/pc/eio-cxx.pc.in b/pc/eio-cxx.pc.in new file mode 100644 index 0000000000..82c6cfa84e --- /dev/null +++ b/pc/eio-cxx.pc.in @@ -0,0 +1,12 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: eio C++ API +Description: Enlightenned Asynchronous Input Output library C++ API. +Requires.private: @requirements_pc_eio@ +Version: @VERSION@ +Libs: -L${libdir} -leio +Libs.private: @requirements_libs_eio@ +Cflags: -I${includedir}/efl-@VMAJ@ -I${includedir}/eio-@VMAJ@ -I${includedir}/eio-cxx-@VMAJ@ diff --git a/pc/emodel-cxx.pc.in b/pc/emodel-cxx.pc.in new file mode 100644 index 0000000000..dce37642ad --- /dev/null +++ b/pc/emodel-cxx.pc.in @@ -0,0 +1,12 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: emodel C++ API +Description: MVC Library C++ API. +Version: @PACKAGE_VERSION@ +Requires.private: @requirements_pc_emodel@ +Libs: -L${libdir} -lemodel +Libs.private: @requirements_libs_emodel@ +Cflags: -I${includedir}/efl-@VMAJ@ -I${includedir}/emodel-@VMAJ@ -I${includedir}/emodel-cxx-@VMAJ@ diff --git a/pc/emodel.pc.in b/pc/emodel.pc.in new file mode 100644 index 0000000000..0d68f11152 --- /dev/null +++ b/pc/emodel.pc.in @@ -0,0 +1,12 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: emodel +Description: MVC Library +Version: @PACKAGE_VERSION@ +Requires.private: @requirements_pc_emodel@ +Libs: -L${libdir} -lemodel +Libs.private: @requirements_libs_emodel@ +Cflags: -I${includedir}/efl-@VMAJ@ -I${includedir}/emodel-@VMAJ@ diff --git a/pkgbuild/PKGBUILD b/pkgbuild/PKGBUILD index afa8ae2d7d..6a17c0b951 100644 --- a/pkgbuild/PKGBUILD +++ b/pkgbuild/PKGBUILD @@ -60,7 +60,7 @@ build() { package_efl() { provides+=("ecore=$pkgver" "eldbus=$pkgver" "edje=$pkgver" "eet=$pkgver" "eeze=$pkgver" "efreet=$pkgver" - "eina=$pkgver" "eio=$pkgver" "embryo=$pkgver" "emotion=$pkgver" + "eina=$pkgver" "eio=$pkgver" "embryo=$pkgver" "emotion=$pkgver" "emodel=$pkgver" "ephysics=$pkgver" "ethumb=$pkgver" "evas=$pkgver") conflicts+=('ecore' 'edje' 'eet' 'eeze' 'efreet' 'eina' 'eio' 'embryo' 'emotion' 'ethumb' 'evas') diff --git a/src/Makefile.am b/src/Makefile.am index 77403a7d87..8462c3a589 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -10,7 +10,9 @@ EOLIAN_FLAGS = -I$(srcdir)\ -I$(srcdir)/lib/efl/interfaces \ -I$(srcdir)/lib/ecore_audio \ -I$(srcdir)/lib/ecore \ - -I$(srcdir)/lib/ecore_con + -I$(srcdir)/lib/ecore_con \ + -I$(srcdir)/lib/emodel \ + -I$(srcdir)/lib/eio DIST_SUBDIRS = SUBDIRS = @@ -65,6 +67,7 @@ include Makefile_Eeze.am include Makefile_EPhysics.am include Makefile_Edje.am include Makefile_Emotion.am +include Makefile_Emodel.am include Makefile_Ethumb.am include Makefile_Ethumb_Client.am @@ -77,6 +80,8 @@ include Makefile_Eo_Cxx.am include Makefile_Efl_Cxx.am include Makefile_Edje_Cxx.am include Makefile_Evas_Cxx.am +include Makefile_Emodel_Cxx.am +include Makefile_Eio_Cxx.am include Makefile_Elua.am include Makefile_Elocation.am diff --git a/src/Makefile_Efl_Cxx.am b/src/Makefile_Efl_Cxx.am index fbcc5632ca..9df7c60bdd 100644 --- a/src/Makefile_Efl_Cxx.am +++ b/src/Makefile_Efl_Cxx.am @@ -19,7 +19,7 @@ generated_efl_cxx_bindings = \ lib/efl/interfaces/efl_gfx_gradient_radial.eo.hh lib/efl/Efl.hh: $(generated_efl_cxx_bindings) - @echo @ECHO_E@ "#ifndef EFL_CXX_EDJE_HH\n#define EFL_CXX_EDJE_HH\n" > $(top_builddir)/src/lib/efl/Efl.hh + @echo @ECHO_E@ "#ifndef EFL_CXX_HH\n#define EFL_CXX_HH\n" > $(top_builddir)/src/lib/efl/Efl.hh @echo @ECHO_E@ "#ifdef EFL_BETA_API_SUPPORT" >> $(top_builddir)/src/lib/efl/Efl.hh @for i in $(generated_efl_cxx_bindings); do echo "#include <$$(basename $$i)>" >> $(top_builddir)/src/lib/efl/Efl.hh; done @echo @ECHO_E@ "#endif\n\n#endif\n" >> $(top_builddir)/src/lib/efl/Efl.hh diff --git a/src/Makefile_Eio.am b/src/Makefile_Eio.am index 47f746f2c8..c42c5eb292 100644 --- a/src/Makefile_Eio.am +++ b/src/Makefile_Eio.am @@ -1,10 +1,24 @@ ### Library +EIO_EOS = \ + lib/eio/eio_model.eo + +EIO_EOS_H = $(EIO_EOS:%.eo=%.eo.h) +EIO_EOS_C = $(EIO_EOS:%.eo=%.eo.c) + +BUILT_SOURCES += $(EIO_EOS_C) $(EIO_EOS_H) + +eioeolianfilesdir = $(datadir)/eolian/include/eio-@VMAJ@ +eioeolianfiles_DATA = $(EIO_EOS) + lib_LTLIBRARIES += lib/eio/libeio.la +EXTRA_DIST += $(eioeolianfiles_DATA) installed_eiomainheadersdir = $(includedir)/eio-@VMAJ@ + dist_installed_eiomainheaders_DATA = lib/eio/Eio.h lib/eio/eio_inline_helper.x +nodist_installed_eiomainheaders_DATA = $(EIO_EOS_H) lib_eio_libeio_la_SOURCES = \ lib/eio/eio_dir.c \ @@ -16,6 +30,8 @@ lib/eio/eio_monitor.c \ lib/eio/eio_monitor_poll.c \ lib/eio/eio_single.c \ lib/eio/eio_xattr.c \ +lib/eio/eio_model.c \ +lib/eio/eio_model_private.h \ lib/eio/eio_private.h if HAVE_INOTIFY @@ -30,9 +46,9 @@ endif endif endif -lib_eio_libeio_la_CPPFLAGS = -I$(top_builddir)/src/lib/efl @EIO_CFLAGS@ -lib_eio_libeio_la_LIBADD = @EIO_LIBS@ -lib_eio_libeio_la_DEPENDENCIES = @EIO_INTERNAL_LIBS@ +lib_eio_libeio_la_CPPFLAGS = -I$(top_builddir)/src/lib/efl @EIO_CFLAGS@ @EMODEL_CFLAGS@ +lib_eio_libeio_la_LIBADD = @EIO_LIBS@ @EMODEL_LIBS@ +lib_eio_libeio_la_DEPENDENCIES = @EIO_INTERNAL_LIBS@ @EMODEL_INTERNAL_LIBS@ lib_eio_libeio_la_LDFLAGS = @EFL_LTLIBRARY_FLAGS@ if HAVE_NOTIFY_COCOA lib_eio_libeio_la_LDFLAGS += -framework CoreServices diff --git a/src/Makefile_Eio_Cxx.am b/src/Makefile_Eio_Cxx.am new file mode 100644 index 0000000000..3f5237169c --- /dev/null +++ b/src/Makefile_Eio_Cxx.am @@ -0,0 +1,22 @@ +if HAVE_CXX11 + +### Generated headers + +generated_eio_cxx_bindings = lib/eio/eio_model.eo.hh + +lib/eio/Eio.hh: $(generated_eio_cxx_bindings) + @echo @ECHO_E@ "#ifndef EFL_CXX_EIO_HH\n#define EFL_CXX_EIO_HH\n" > $(top_builddir)/src/lib/eio/Eio.hh + @echo @ECHO_E@ "#ifdef EFL_BETA_API_SUPPORT" >> $(top_builddir)/src/lib/eio/Eio.hh + @for i in $(generated_eio_cxx_bindings); do echo "#include <$$(basename $$i)>" >> $(top_builddir)/src/lib/eio/Eio.hh; done + @echo @ECHO_E@ "#endif\n\n#endif\n" >> $(top_builddir)/src/lib/eio/Eio.hh + +generated_eio_cxx_all = \ + $(generated_eio_cxx_bindings) \ + lib/eio/Eio.hh + +CLEANFILES += $(generated_eio_cxx_all) + +installed_eiocxxmainheadersdir = $(includedir)/eio-cxx-@VMAJ@/ +nodist_installed_eiocxxmainheaders_DATA = $(generated_eio_cxx_all) + +endif diff --git a/src/Makefile_Emodel.am b/src/Makefile_Emodel.am new file mode 100644 index 0000000000..4585af429f --- /dev/null +++ b/src/Makefile_Emodel.am @@ -0,0 +1,78 @@ + +### Library + +EMODEL_EOS = lib/emodel/emodel.eo + +EMODEL_EOS_H = $(EMODEL_EOS:%.eo=%.eo.h) +EMODEL_EOS_C = $(EMODEL_EOS:%.eo=%.eo.c) + +BUILT_SOURCES += $(EMODEL_EOS_C) $(EMODEL_EOS_H) + +dist_installed_emodelmainheaders_DATA = \ +lib/emodel/Emodel.h \ +lib/emodel/Emodel_Common.h + +nodist_installed_emodelmainheaders_DATA = $(EMODEL_EOS_H) + +emodeleolianfilesdir = $(datadir)/eolian/include/emodel-@VMAJ@ +emodeleolianfiles_DATA = $(EMODEL_EOS) + +lib_LTLIBRARIES += lib/emodel/libemodel.la +EXTRA_DIST += $(emodeleolianfiles_DATA) + +installed_emodelmainheadersdir = $(includedir)/emodel-@VMAJ@ + +lib_emodel_libemodel_la_SOURCES = \ +lib/emodel/emodel.c + +lib_emodel_libemodel_la_CPPFLAGS = -I$(top_builddir)/src/lib/efl \ +-I$(top_builddir)/src/lib/emodel \ +-I$(top_srcdir)/src/lib/emodel \ +-I$(top_builddir)/src/lib/eo \ +-I$(top_srcdir)/src/lib/eo \ +-I$(top_builddir)/src/lib/ecore \ +-I$(top_srcdir)/src/lib/ecore \ +-I$(top_builddir)/src/lib/eina \ +-I$(top_srcdir)/src/lib/eina \ +-DPACKAGE_BIN_DIR=\"$(bindir)\" \ +-DPACKAGE_LIB_DIR=\"$(libdir)\" \ +-DPACKAGE_DATA_DIR=\"$(datadir)/edje\" \ +-DPACKAGE_BUILD_DIR=\"`pwd`/$(top_builddir)\" \ +-DPACKAGE_SRC_DIR=\"`pwd`/$(top_srcdir)\" \ +@EMODEL_CFLAGS@ +lib_emodel_libemodel_la_LIBADD = @EMODEL_LIBS@ +lib_emodel_libemodel_la_DEPENDENCIES = @EMODEL_INTERNAL_LIBS@ @EINA_INTERNAL_LIBS@ @EO_INTERNAL_LIBS@ @ECORE_INTERNAL_LIBS@ + +if EFL_ENABLE_TESTS +EXTRA_DIST += $(emodeleolianfiles_DATA) + +check_PROGRAMS += tests/emodel/emodel_suite +TESTS += tests/emodel/emodel_suite + +tests_emodel_emodel_suite_SOURCES = \ +tests/emodel/emodel_suite.c \ +tests/emodel/emodel_test_file.c \ +tests/emodel/emodel_test_monitor_add.c + +tests_emodel_emodel_suite_CPPFLAGS = -I$(top_builddir)/src/lib/efl \ +-I$(top_builddir)/src/lib/emodel \ +-I$(top_srcdir)/src/lib/emodel \ +-I$(top_builddir)/src/lib/ecore \ +-I$(top_srcdir)/src/lib/ecore \ +-I$(top_builddir)/src/lib/eio \ +-I$(top_srcdir)/src/lib/eio \ +-I$(top_builddir)/src/lib/eina \ +-I$(top_srcdir)/src/lib/eina \ +-DTESTS_WD=\"`pwd`\" \ +-DTESTS_SRC_DIR=\"$(top_srcdir)/src/tests/emodel\" \ +-DPACKAGE_BUILD_DIR=\"`pwd`/$(top_builddir)/src/tests/emodel\" \ +-DTESTS_BUILD_DIR=PACKAGE_BUILD_DIR \ +@CHECK_CFLAGS@ \ +@EINA_CFLAGS@ \ +@EMODEL_CFLAGS@ \ +@EO_CFLAGS@ \ +@EIO_CFLAGS@ +tests_emodel_emodel_suite_LDADD = @CHECK_LIBS@ @USE_EMODEL_LIBS@ @USE_EINA_LIBS@ @USE_EO_LIBS@ @USE_EIO_LIBS@ @USE_ECORE_LIBS@ +tests_emodel_emodel_suite_DEPENDENCIES = @USE_EMODEL_INTERNAL_LIBS@ @USE_EINA_INTERNAL_LIBS@ @USE_EO_INTERNAL_LIBS@ @USE_EIO_INTERNAL_LIBS@ @USE_ECORE_INTERNAL_LIBS@ + +endif diff --git a/src/Makefile_Emodel_Cxx.am b/src/Makefile_Emodel_Cxx.am new file mode 100644 index 0000000000..f6984b48a9 --- /dev/null +++ b/src/Makefile_Emodel_Cxx.am @@ -0,0 +1,22 @@ +if HAVE_CXX11 + +### Generated headers + +generated_emodel_cxx_bindings = lib/emodel/emodel.eo.hh + +lib/emodel/Emodel.hh: $(generated_emodel_cxx_bindings) + @echo @ECHO_E@ "#ifndef EFL_CXX_EMODEL_HH\n#define EFL_CXX_EMODEL_HH\n" > $(top_builddir)/src/lib/emodel/Emodel.hh + @echo @ECHO_E@ "#ifdef EFL_BETA_API_SUPPORT" >> $(top_builddir)/src/lib/emodel/Emodel.hh + @for i in $(generated_emodel_cxx_bindings); do echo "#include <$$(basename $$i)>" >> $(top_builddir)/src/lib/emodel/Emodel.hh; done + @echo @ECHO_E@ "#endif\n\n#endif\n" >> $(top_builddir)/src/lib/emodel/Emodel.hh + +generated_emodel_cxx_all = \ + $(generated_emodel_cxx_bindings) \ + lib/emodel/Emodel.hh + +CLEANFILES += $(generated_emodel_cxx_all) + +installed_emodelcxxmainheadersdir = $(includedir)/emodel-cxx-@VMAJ@/ +nodist_installed_emodelcxxmainheaders_DATA = $(generated_emodel_cxx_all) + +endif diff --git a/src/examples/eio/Makefile.am b/src/examples/eio/Makefile.am index a424f77084..c80f74739a 100644 --- a/src/examples/eio/Makefile.am +++ b/src/examples/eio/Makefile.am @@ -22,6 +22,7 @@ eio_file_copy eio_file_ls_SOURCES = eio_file_ls.c eio_file_ls_LDADD = \ $(top_builddir)/src/lib/eio/libeio.la \ +$(top_builddir)/src/lib/emodel/libemodel.la \ $(top_builddir)/src/lib/eo/libeo.la \ $(top_builddir)/src/lib/ecore/libecore.la \ $(top_builddir)/src/lib/eet/libeet.la \ @@ -32,6 +33,7 @@ $(top_builddir)/src/lib/eina/libeina.la \ eio_file_copy_SOURCES = eio_file_copy.c eio_file_copy_LDADD = \ $(top_builddir)/src/lib/eio/libeio.la \ +$(top_builddir)/src/lib/emodel/libemodel.la \ $(top_builddir)/src/lib/eo/libeo.la \ $(top_builddir)/src/lib/ecore/libecore.la \ $(top_builddir)/src/lib/eet/libeet.la \ diff --git a/src/lib/eio/eio_model.c b/src/lib/eio/eio_model.c new file mode 100644 index 0000000000..454f1b1a31 --- /dev/null +++ b/src/lib/eio/eio_model.c @@ -0,0 +1,774 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include +#include + +#include "eio_model_private.h" + +#define MY_CLASS EIO_MODEL_CLASS +#define MY_CLASS_NAME "Eio_Model" + +static Eina_Value_Struct_Desc *EIO_MODEL_PROPERTIES_DESC = NULL; +static void _eio_prop_set_error_cb(void *, Eio_File *, int); +static void _eio_model_emodel_properties_load(Eo *, Eio_Model_Data *); +static void _eio_model_emodel_children_load(Eo *, Eio_Model_Data *); + +static void +_load_set(Eio_Model_Data *priv, Emodel_Load load) +{ + if ((priv->load.status & (EMODEL_LOAD_STATUS_LOADED | EMODEL_LOAD_STATUS_LOADING)) && + (load.status & (EMODEL_LOAD_STATUS_LOADED | EMODEL_LOAD_STATUS_LOADING))) + { + load.status = priv->load.status | load.status; + switch (load.status) + { + case EMODEL_LOAD_STATUS_LOADED_PROPERTIES: + load.status &= ~EMODEL_LOAD_STATUS_LOADING_PROPERTIES; + break; + case EMODEL_LOAD_STATUS_LOADING_PROPERTIES: + load.status &= ~EMODEL_LOAD_STATUS_LOADED_PROPERTIES; + break; + case EMODEL_LOAD_STATUS_LOADED_CHILDREN: + load.status &= ~EMODEL_LOAD_STATUS_LOADING_CHILDREN; + break; + case EMODEL_LOAD_STATUS_LOADING_CHILDREN: + load.status &= ~EMODEL_LOAD_STATUS_LOADED_CHILDREN; + break; + default: break; + } + } + + if (priv->load.status != load.status) + { + priv->load.status = load.status; + eo_do(priv->obj, eo_event_callback_call(EMODEL_EVENT_LOAD_STATUS, &load)); + } +} + +static void +_stat_pro_set(Eio_Model_Data *priv, int prop_id, const Eina_Value *value, Emodel_Property_Event *evt) +{ + Eina_Value old_value; + int changed; + Emodel_Property_Pair *pair = NULL; + const char *prop = EIO_MODEL_PROPERTIES_DESC->members[prop_id].name; + + eina_value_struct_value_get(priv->properties, prop, &old_value); + changed = eina_value_compare(&old_value, value); + + if(changed) eina_value_struct_value_set(priv->properties, prop, value); + eina_value_flush(&old_value); + if(!changed) return; + + pair = calloc(1, sizeof(Emodel_Property_Pair)); + EINA_SAFETY_ON_NULL_RETURN(pair); + if(!eina_value_copy((Eina_Value*)value, &pair->value)) + { + free(pair); + return; + } + + pair->property = eina_stringshare_add(prop); + evt->changed_properties = eina_list_append(evt->changed_properties, pair); +} + +/** + * Callbacks + * Property + */ +static void +_eio_stat_done_cb(void *data, Eio_File *handler EINA_UNUSED, const Eina_Stat *stat) +{ + Emodel_Property_Event evt; + Eina_Value value; + Eio_Model_Data *priv = data; + Emodel_Load load; + EINA_SAFETY_ON_FALSE_RETURN(eo_ref_get(priv->obj)); + + priv->stat = stat; + memset(&evt, 0, sizeof(Emodel_Property_Event)); + + // Setup for Eina_Bool + eina_value_setup(&value, EINA_VALUE_TYPE_INT); + eina_value_set(&value, eio_file_is_dir(stat)); + _stat_pro_set(priv, EIO_MODEL_PROP_IS_DIR, (const Eina_Value*)&value, &evt); + eina_value_flush(&value); + + // Setup for Eina_Bool + eina_value_setup(&value, EINA_VALUE_TYPE_INT); + eina_value_set(&value, eio_file_is_lnk(stat)); + _stat_pro_set(priv, EIO_MODEL_PROP_IS_LNK, (const Eina_Value*)&value, &evt); + eina_value_flush(&value); + + // Setup for double + eina_value_setup(&value, EINA_VALUE_TYPE_TIMEVAL); + eina_value_set(&value, eio_file_mtime(stat)); + _stat_pro_set(priv, EIO_MODEL_PROP_MTIME, (const Eina_Value*)&value, &evt); + eina_value_flush(&value); + + // Setup for long long + eina_value_setup(&value, EINA_VALUE_TYPE_INT64); + eina_value_set(&value, eio_file_size(stat)); + _stat_pro_set(priv, EIO_MODEL_PROP_SIZE, (const Eina_Value*)&value, &evt); + eina_value_flush(&value); + + if (evt.changed_properties != NULL) + { + Emodel_Property_Pair *pair; + eo_do(priv->obj, eo_event_callback_call(EMODEL_EVENT_PROPERTIES_CHANGED, &evt)); + EINA_LIST_FREE(evt.changed_properties, pair) + { + eina_stringshare_del(pair->property); + eina_value_flush(&pair->value); + free(pair); + } + } + + load.status = EMODEL_LOAD_STATUS_LOADED_PROPERTIES; + _load_set(priv, load); + + if (priv->load_pending & EMODEL_LOAD_STATUS_LOADED_CHILDREN) + _eio_model_emodel_children_load(priv->obj, priv); +} + +static void +_eio_progress_cb(void *data EINA_UNUSED, Eio_File *handler EINA_UNUSED, const Eio_Progress *info EINA_UNUSED) +{ + //TODO: implement +} + +static void +_eio_move_done_cb(void *data, Eio_File *handler EINA_UNUSED) +{ + Emodel_Property_Event evt; + Emodel_Property_Pair pair_path, pair_filename; + Eio_Model_Data *priv = data; + Eina_Value_Struct_Desc *desc = EIO_MODEL_PROPERTIES_DESC; + + EINA_SAFETY_ON_FALSE_RETURN(eo_ref_get(priv->obj)); + + memset(&evt, 0, sizeof(Emodel_Property_Event)); + + /** + * When mv is executed we update our values and + * notify both path and filename properties listeners. + */ + pair_path.property = eina_stringshare_add(desc->members[EIO_MODEL_PROP_PATH].name); + eina_value_struct_set(priv->properties, pair_path.property, priv->path); + eina_value_struct_value_get(priv->properties, pair_path.property, &pair_path.value); + evt.changed_properties = eina_list_append(evt.changed_properties, &pair_path); + + pair_filename.property = eina_stringshare_add(desc->members[EIO_MODEL_PROP_FILENAME].name); + eina_value_struct_set(priv->properties, pair_filename.property, basename(priv->path)); + eina_value_struct_value_get(priv->properties, pair_filename.property, &pair_filename.value); + evt.changed_properties = eina_list_append(evt.changed_properties, &pair_filename); + + eo_do(priv->obj, eo_event_callback_call(EMODEL_EVENT_PROPERTIES_CHANGED, &evt)); + + eina_stringshare_del(pair_path.property); + eina_stringshare_del(pair_filename.property); + eina_value_flush(&pair_filename.value); + eina_value_flush(&pair_path.value); + + eina_list_free(evt.changed_properties); +} + +static void +_eio_error_cb(void *data EINA_UNUSED, Eio_File *handler EINA_UNUSED, int error) +{ + if(error != 0) + { + fprintf(stderr, "Error: %s : %d: %s\n", __FUNCTION__, error, strerror(errno)); + EINA_SAFETY_ON_FALSE_RETURN(EINA_FALSE); /**< force check error only to be more verbose */ + } + fprintf(stdout, "%s : %d\n", __FUNCTION__, error); +} + +static void +_eio_prop_set_error_cb(void *data EINA_UNUSED, Eio_File *handler EINA_UNUSED, int error EINA_UNUSED) +{ + fprintf(stdout, "%s : %d\n", __FUNCTION__, error); +} + + +/** + * Callbacks + * Ecore Events + */ +static Eina_Bool + _emodel_evt_added_ecore_cb(void *data EINA_UNUSED, int type EINA_UNUSED, void *event EINA_UNUSED) +{ + Eio_Monitor_Event *evt = (Eio_Monitor_Event*)event; + Eio_Model_Data *priv = data; + Emodel_Children_Event cevt; + Eina_Value path; + + if(priv->children_list) + { + cevt.child = eo_add_ref(EIO_MODEL_CLASS, priv->obj, eio_model_path_set(evt->filename)); + priv->children_list = eina_list_append(priv->children_list, cevt.child); + cevt.index = eina_list_count(priv->children_list); + + eina_value_setup(&path, EINA_VALUE_TYPE_STRING); + eina_value_set(&path, evt->filename); + eo_do(cevt.child, eio_model_children_filter_set(priv->filter_cb, priv->filter_userdata)); + eina_value_flush(&path); + + eo_do(priv->obj, eo_event_callback_call(EMODEL_EVENT_CHILD_ADDED, &cevt)); + } + + return EINA_TRUE; +} + +static Eina_Bool +_emodel_evt_deleted_ecore_cb(void *data EINA_UNUSED, int type EINA_UNUSED, void *event EINA_UNUSED) +{ + Eio_Monitor_Event *evt = (Eio_Monitor_Event*)event; + Eio_Model_Data *priv = data; + + if(priv->children_list) + { + Eina_List* cur = priv->children_list; + int i; + for(i = 0; cur; ++i, cur = cur->next) + { + Eio_Model_Data *cur_priv = eo_data_scope_get(cur->data, MY_CLASS); + if(strcmp(cur_priv->path, evt->filename) == 0) + break; + } + if(cur) + { + Emodel_Children_Event cevt; + + + cevt.index = i; + cevt.child = cur->data; + + eo_do(priv->obj, eo_event_callback_call(EMODEL_EVENT_CHILD_REMOVED, &cevt)); + + priv->children_list = eina_list_remove_list(priv->children_list, cur); + eo_unref(cevt.child); + } + } + + return EINA_TRUE; +} + +static void +_eio_monitors_list_load(Eio_Model_Data *priv) +{ + priv->mon.mon_event_child_add[0] = EIO_MONITOR_DIRECTORY_CREATED; + priv->mon.mon_event_child_add[1] = EIO_MONITOR_FILE_CREATED; + priv->mon.mon_event_child_add[2] = EIO_MONITOR_ERROR; + priv->mon.mon_event_child_del[0] = EIO_MONITOR_DIRECTORY_DELETED; + priv->mon.mon_event_child_del[1] = EIO_MONITOR_FILE_DELETED; + priv->mon.mon_event_child_del[2] = EIO_MONITOR_ERROR; +} + +/** + * Callbacks + * Child Del + */ +static Eina_Bool +_eio_filter_child_del_cb(void *data EINA_UNUSED, Eio_File *handler EINA_UNUSED, const Eina_File_Direct_Info *info EINA_UNUSED) +{ + return EINA_TRUE; +} + +static void +_eio_progress_child_del_cb(void *data EINA_UNUSED, Eio_File *handler EINA_UNUSED, const Eio_Progress *info EINA_UNUSED) +{} + +static void +_eio_done_unlink_cb(void *data, Eio_File *handler EINA_UNUSED) +{ + Eio_Model_Data *priv = data; + + EINA_SAFETY_ON_NULL_RETURN(priv); + EINA_SAFETY_ON_NULL_RETURN(priv->obj); + + eo_unref(priv->obj); +} + +static void +_eio_error_unlink_cb(void *data EINA_UNUSED, Eio_File *handler EINA_UNUSED, int error) +{ + Eio_Model_Data *priv = data; + + fprintf(stdout, "%s : %d\n", __FUNCTION__, error); + + eo_unref(priv->obj); +} + + +/** + * Interfaces impl. + */ +static Emodel_Load_Status +_eio_model_emodel_properties_list_get(Eo *obj EINA_UNUSED, + Eio_Model_Data *_pd, Eina_List * const* properties_list) +{ + Eio_Model_Data *priv = _pd; + unsigned int i; + + EINA_SAFETY_ON_NULL_RETURN_VAL(priv, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(priv->obj, EINA_FALSE); + + if(priv->properties_list == NULL) + { + Eina_Value_Struct_Desc *desc = EIO_MODEL_PROPERTIES_DESC; + for(i = 0; i < desc->member_count; ++i) + priv->properties_list = eina_list_append(priv->properties_list, desc->members[i].name); + } + + *(Eina_List **)properties_list = priv->properties_list; + + return priv->load.status; +} + +/** + * Property Fetch //carlos + */ +static Emodel_Load_Status +_eio_model_emodel_property_get(Eo *obj EINA_UNUSED, Eio_Model_Data *priv, const char *property, Eina_Value *value) +{ + Eina_Value _v; + EINA_SAFETY_ON_NULL_RETURN_VAL(property, EMODEL_LOAD_STATUS_ERROR); + EINA_SAFETY_ON_NULL_RETURN_VAL(priv, EMODEL_LOAD_STATUS_ERROR); + EINA_SAFETY_ON_NULL_RETURN_VAL(priv->obj, EMODEL_LOAD_STATUS_ERROR); + + if (eina_value_struct_value_get(priv->properties, property, &_v) == EINA_TRUE) + { + eina_value_copy(&_v, value); + } + + return priv->load.status; +} + +/** + * Property Set + */ +static Emodel_Load_Status +_eio_model_emodel_property_set(Eo *obj EINA_UNUSED, Eio_Model_Data *priv, const char * property, Eina_Value value) +{ + char *dest; + Eina_Value v = value; + + EINA_SAFETY_ON_NULL_RETURN_VAL(property, EINA_FALSE); + + if (strcmp(property, "path") != 0) + return EINA_FALSE; + + dest = eina_value_to_string(&v); + if (priv->path == NULL) + { + priv->path = dest; + + fprintf(stdout, " path %s filename %s\n", priv->path, basename(priv->path)); + + eina_value_struct_set(priv->properties, "path", priv->path); + eina_value_struct_set(priv->properties, "filename", eina_stringshare_add(basename(priv->path))); + + _eio_monitors_list_load(priv); + + _eio_move_done_cb(priv, NULL); + + if (priv->load_pending & EMODEL_LOAD_STATUS_LOADED_PROPERTIES) + _eio_model_emodel_properties_load(obj, priv); + + if (priv->load_pending & EMODEL_LOAD_STATUS_LOADED_CHILDREN) + _eio_model_emodel_children_load(obj, priv); + + return priv->load.status; + } + + priv->file = eio_file_move(priv->path, dest, _eio_progress_cb, _eio_move_done_cb, _eio_prop_set_error_cb, priv); + free(priv->path); + priv->path = dest; + + return priv->load.status; +} +/** + * Children Count Get + */ +static Emodel_Load_Status +_eio_model_emodel_children_count_get(Eo *obj EINA_UNUSED, Eio_Model_Data *priv, unsigned int *children_count) +{ + /**< eina_list_count returns 'unsigned int' */ + *children_count = eina_list_count(priv->children_list); + return priv->load.status; +} + +/** + * Properties Load + */ + static void +_eio_model_emodel_properties_load(Eo *obj EINA_UNUSED, Eio_Model_Data *priv) +{ + Emodel_Load load; + if (priv->path == NULL) + { + priv->load_pending |= EMODEL_LOAD_STATUS_LOADED_PROPERTIES; + return; + } + priv->load_pending &= ~EMODEL_LOAD_STATUS_LOADED_PROPERTIES; + + if (!(priv->load.status & (EMODEL_LOAD_STATUS_LOADED_PROPERTIES | EMODEL_LOAD_STATUS_LOADING_PROPERTIES))) + { + load.status = EMODEL_LOAD_STATUS_LOADING_PROPERTIES; + _load_set(priv, load); + priv->file = eio_file_direct_stat(priv->path, _eio_stat_done_cb, _eio_error_cb, priv); + } +} + +static void +_eio_model_emodel_monitor_add(Eio_Model_Data *priv) +{ + if(!priv->monitor) + { + priv->monitor = eio_monitor_add(priv->path); + int i = 0; + for(i = 0; priv->mon.mon_event_child_add[i] != EIO_MONITOR_ERROR ; ++i) + priv->mon.ecore_child_add_handler[i] = + ecore_event_handler_add(priv->mon.mon_event_child_add[i], _emodel_evt_added_ecore_cb, priv); + for(i = 0; priv->mon.mon_event_child_del[i] != EIO_MONITOR_ERROR ; ++i) + priv->mon.ecore_child_add_handler[i] = + ecore_event_handler_add(priv->mon.mon_event_child_del[i], _emodel_evt_deleted_ecore_cb, priv); + } +} + +/* + * Callbacks + * Children Load + */ +static Eina_Bool +_eio_filter_children_load_cb(void *data, Eio_File *handler, const Eina_File_Direct_Info *info) +{ + Eio_Model_Data *priv = data; + EINA_SAFETY_ON_NULL_RETURN_VAL(priv, EINA_FALSE); + + if (priv->filter_cb) + { + return priv->filter_cb(priv->filter_userdata, handler, info); + } + + return EINA_TRUE; +} + +static void +_eio_main_children_load_cb(void *data, Eio_File *handler EINA_UNUSED, const Eina_File_Direct_Info *info) +{ + Eo *child; + Eio_Model_Data *priv = data; + EINA_SAFETY_ON_NULL_RETURN(priv); + + child = eo_add_ref(MY_CLASS, NULL, eio_model_path_set(info->path)); + if (priv->filter_cb) + { + eo_do(child, eio_model_children_filter_set(priv->filter_cb, priv->filter_userdata)); + } + priv->children_list = eina_list_append(priv->children_list, child); +} + +static void +_eio_done_children_load_cb(void *data, Eio_File *handler EINA_UNUSED) +{ + unsigned long count; + Eio_Model_Data *priv = data; + Emodel_Load load; + EINA_SAFETY_ON_NULL_RETURN(priv); + + count = eina_list_count(priv->children_list); + load.status = EMODEL_LOAD_STATUS_LOADED_CHILDREN; + + _load_set(priv, load); + eo_do(priv->obj, eo_event_callback_call(EMODEL_EVENT_CHILDREN_COUNT_CHANGED, &count)); +} + +static void +_eio_error_children_load_cb(void *data, Eio_File *handler EINA_UNUSED, int error) +{ + Eio_Model_Data *priv = data; + Eo *child; + Emodel_Load load; + fprintf(stderr, "%s: err=%d\n", __FUNCTION__, error); + EINA_LIST_FREE(priv->children_list, child) + eo_unref(child); + + load.status = EMODEL_LOAD_STATUS_LOADED_CHILDREN; + + _load_set(priv, load); +} + +/** + * Children Load + */ +static void +_eio_model_emodel_children_load(Eo *obj EINA_UNUSED, Eio_Model_Data *priv) +{ + Emodel_Load load; + if (priv->path == NULL) + { + priv->load_pending |= EMODEL_LOAD_STATUS_LOADED_CHILDREN; + return; + } + priv->load_pending &= ~EMODEL_LOAD_STATUS_LOADED_CHILDREN; + + if (!(priv->load.status & (EMODEL_LOAD_STATUS_LOADED_CHILDREN | EMODEL_LOAD_STATUS_LOADING_CHILDREN))) + { + _eio_model_emodel_monitor_add(priv); + + load.status = EMODEL_LOAD_STATUS_LOADING_CHILDREN; + _load_set(priv, load); + eio_file_direct_ls(priv->path, _eio_filter_children_load_cb, + _eio_main_children_load_cb, _eio_done_children_load_cb, + _eio_error_children_load_cb, priv); + } +} + +/** + * Load + */ + static void +_eio_model_emodel_load(Eo *obj, Eio_Model_Data *priv) +{ + priv->load_pending |= EMODEL_LOAD_STATUS_LOADED_CHILDREN; + _eio_model_emodel_properties_load(obj, priv); +} + +/** + * Load status get + */ +static Emodel_Load_Status +_eio_model_emodel_load_status_get(Eo *obj EINA_UNUSED, Eio_Model_Data *priv) +{ + return priv->load.status; +} + +/** + * Unload + */ +static void +_eio_model_emodel_unload(Eo *obj EINA_UNUSED, Eio_Model_Data *priv) +{ + Emodel_Load load; + if (!(priv->load.status & EMODEL_LOAD_STATUS_UNLOADED)) + { + Eo *child; + EINA_LIST_FREE(priv->children_list, child) + { + eo_unref(child); + } + + load.status = EMODEL_LOAD_STATUS_UNLOADED; + _load_set(priv, load); + } +} + +static void +_eio_model_children_filter_set(Eo *obj EINA_UNUSED, Eio_Model_Data *priv, Eio_Filter_Direct_Cb filter_cb, void *data) +{ + priv->filter_cb = filter_cb; + priv->filter_userdata = data; +} + +/** + * Child Add + */ +static Eo * +_eio_model_emodel_child_add(Eo *obj EINA_UNUSED, Eio_Model_Data *priv EINA_UNUSED) +{ + return eo_add(EIO_MODEL_CLASS, obj); +} + +static void +_eio_model_emodel_child_del_stat(void* data, Eio_File* handler EINA_UNUSED, const Eina_Stat* stat) +{ + Eo* child = data; + Eio_Model_Data *child_priv = eo_data_scope_get(child, MY_CLASS); + + if(eio_file_is_dir(stat)) + eio_dir_unlink(child_priv->path, + _eio_filter_child_del_cb, + _eio_progress_child_del_cb, + _eio_done_unlink_cb, + _eio_error_unlink_cb, + child_priv); + else + eio_file_unlink(child_priv->path, _eio_done_unlink_cb, _eio_error_unlink_cb, child_priv); +} + +/** + * Child Remove + */ +static Emodel_Load_Status +_eio_model_emodel_child_del(Eo *obj EINA_UNUSED, Eio_Model_Data *priv, Eo *child) +{ + Eio_Model_Data *child_priv; + EINA_SAFETY_ON_NULL_RETURN_VAL(child, EMODEL_LOAD_STATUS_ERROR); + + if (priv->children_list != NULL) + { + priv->children_list = eina_list_remove(priv->children_list, child); + } + + child_priv = eo_data_scope_get(child, MY_CLASS); + EINA_SAFETY_ON_NULL_RETURN_VAL(child_priv, EMODEL_LOAD_STATUS_ERROR); + + eio_file_direct_stat(child_priv->path, &_eio_model_emodel_child_del_stat + , &_eio_error_unlink_cb, child); + eo_ref(child); + return priv->load.status; +} + +/** + * Children Slice Get + * TODO/XXX/FIXME: Untested code - validate this implementation + */ +static Emodel_Load_Status +_eio_model_emodel_children_slice_get(Eo *obj EINA_UNUSED, Eio_Model_Data *priv, + unsigned start, unsigned count, Eina_Accessor **children_accessor) +{ + Eo *child; + Eina_List *l, *ln, *lr = NULL; + + /** + * children must be already loaded otherwise we do nothing + * and parameter is set to NULL. + */ + + if(!(priv->load.status & EMODEL_LOAD_STATUS_LOADED_CHILDREN)) + { + /** + * Status should be in either unloaded state or unitialized + * so we simply return without much alarm. + */ + *children_accessor = NULL; + return priv->load.status; + } + + if((start == 0) && (count == 0)) /* this is full data */ + { + /* + * children_accessor will be set to NULL by + * eina_list_accessor_new if the later fails. + */ + *children_accessor = eina_list_accessor_new(priv->children_list); + } + else /* this is only slice */ + { + ln = eina_list_nth_list(priv->children_list, (start-1)); + if(!ln) + { + /** + * In error, we make it more verbose + * by forcing warning to be displayed on terminal. + */ + *children_accessor = NULL; + EINA_SAFETY_ON_NULL_RETURN_VAL(NULL, priv->load.status); + } + EINA_LIST_FOREACH(ln, l, child) + { + eo_ref(child); + lr = eina_list_append(lr, child); + if (eina_list_count(lr) == count) + break; + } + *children_accessor = eina_list_accessor_new(lr); + } + + return priv->load.status; +} + +static void +_struct_properties_init(void) +{ + typedef struct _This_Eio_Properties + { + const char *filename; + const char *path; + double mtime; + int is_dir; + int is_lnk; + int size; + } This_Eio_Properties; + + static Eina_Value_Struct_Member prop_members[] = { + EINA_VALUE_STRUCT_MEMBER(NULL, This_Eio_Properties, filename), + EINA_VALUE_STRUCT_MEMBER(NULL, This_Eio_Properties, path), + EINA_VALUE_STRUCT_MEMBER(NULL, This_Eio_Properties, mtime), + EINA_VALUE_STRUCT_MEMBER(NULL, This_Eio_Properties, is_dir), + EINA_VALUE_STRUCT_MEMBER(NULL, This_Eio_Properties, is_lnk), + EINA_VALUE_STRUCT_MEMBER(NULL, This_Eio_Properties, size) + }; + //XXX: Check data types + prop_members[EIO_MODEL_PROP_FILENAME].type = EINA_VALUE_TYPE_STRING; + prop_members[EIO_MODEL_PROP_PATH].type = EINA_VALUE_TYPE_STRING; + prop_members[EIO_MODEL_PROP_MTIME].type = EINA_VALUE_TYPE_TIMEVAL; + prop_members[EIO_MODEL_PROP_IS_DIR].type = EINA_VALUE_TYPE_INT; + prop_members[EIO_MODEL_PROP_IS_LNK].type = EINA_VALUE_TYPE_INT; + prop_members[EIO_MODEL_PROP_SIZE].type = EINA_VALUE_TYPE_INT64; + + static Eina_Value_Struct_Desc prop_desc = { + EINA_VALUE_STRUCT_DESC_VERSION, + NULL, // no special operations + prop_members, + EINA_C_ARRAY_LENGTH(prop_members), + sizeof(This_Eio_Properties) + }; + EIO_MODEL_PROPERTIES_DESC = &prop_desc; +} + +/** + * Class definitions + */ +static void +_eio_model_eo_base_constructor(Eo *obj, Eio_Model_Data *priv) +{ + eo_do_super(obj, MY_CLASS, eo_constructor()); + priv->obj = obj; + _struct_properties_init(); + priv->properties = eina_value_struct_new(EIO_MODEL_PROPERTIES_DESC); + EINA_SAFETY_ON_NULL_RETURN(priv->properties); + + priv->load.status = EMODEL_LOAD_STATUS_UNLOADED; + priv->monitor = NULL; +} + +static void +_eio_model_path_set(Eo *obj EINA_UNUSED, Eio_Model_Data *priv, const char *path) +{ + //_eio_model_eo_base_constructor(obj, priv); + priv->path = strdup(path); + + eina_value_struct_set(priv->properties, "path", priv->path); + eina_value_struct_set(priv->properties, "filename", basename(priv->path)); + + priv->monitor = NULL; + _eio_monitors_list_load(priv); +} + +static void +_eio_model_eo_base_destructor(Eo *obj , Eio_Model_Data *priv) +{ + Eo *child; + if(priv->monitor) + eio_monitor_del(priv->monitor); + + eina_list_free(priv->properties_list); + eina_value_free(priv->properties); + + EINA_LIST_FREE(priv->children_list, child) + eo_unref(child); + + free(priv->path); + eo_do_super(obj, MY_CLASS, eo_destructor()); +} + +#include "eio_model.eo.c" diff --git a/src/lib/eio/eio_model.eo b/src/lib/eio/eio_model.eo new file mode 100644 index 0000000000..b8ac23672c --- /dev/null +++ b/src/lib/eio/eio_model.eo @@ -0,0 +1,49 @@ +class Eio.Model (Eo.Base, Emodel) +{ + legacy_prefix: null; + methods { + children_filter_set { + /*@ Set children filter callback. + This function sets, along with user's private data userdata, + the Eio's Eio_Filter_Direct_Cb which is a mid-step + before receiving the real data. Once in filter + callback we can decide, by returning either EINA_FALSE, to abort + the notification or EINA_TRUE to keep it. + @see Eio.h + @see emodel_children_slice_fetch + @def emodel_children_filter_set + @since 1.11 + @in filter_cb + @in userdata */ + params { + Eio_Filter_Direct_Cb filter_cb; /*@ Filter callback */ + void *userdata; /*@ User's private data */ + } + } + path_set { + /*@ Custom Eio_Model constructor. + @def eio_model_constructor + @since 1.11 + @in path */ + params { + @in const(char)* path; /*@ Root path provided by caller */ + } + } + } + implements { + Eo.Base.constructor; + Eo.Base.destructor; + Emodel.properties_list.get; + Emodel.properties_load; + Emodel.property.set; + Emodel.property.get; + Emodel.load; + Emodel.load_status.get; + Emodel.unload; + Emodel.child_add; + Emodel.child_del; + Emodel.children_slice.get; + Emodel.children_count.get; + Emodel.children_load; + } +} diff --git a/src/lib/eio/eio_model.h b/src/lib/eio/eio_model.h new file mode 100644 index 0000000000..e0510702a7 --- /dev/null +++ b/src/lib/eio/eio_model.h @@ -0,0 +1,45 @@ +/** + * @page emodel_eio_main Emodel_Eio + * + * @date 2014 (created) + * + * @brief Emodel_Eio Library Public API Calls + * + * @section toc Table of Contents + * + * @li @ref emodel_eio_main_intro + * + * @section eo_main_intro Introduction + * + * This module targets file operations using Emodel. + + * + * Recommended reading: + * + * @li @ref Emodel + * @li @ref Eo + * @li @ref Eina + * + * @defgroup Emodel_Eio EIO implementation wrapper for Emodel + * + * @addtogroup Emodel_Eio + * @{ + */ + +#ifndef _EMODEL_EIO_H +#define _EMODEL_EIO_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#ifdef __cplusplus +} +#endif +#endif //_EMODEL_EIO_H diff --git a/src/lib/eio/eio_model_private.h b/src/lib/eio/eio_model_private.h new file mode 100644 index 0000000000..26ebdfc819 --- /dev/null +++ b/src/lib/eio/eio_model_private.h @@ -0,0 +1,62 @@ +#ifndef _EIO_MODEL_PRIVATE_H +#define _EIO_MODEL_PRIVATE_H + +#define PROP_LIST_SIZE 7 + +typedef struct _Eio_Model_Data Eio_Model_Data; +//typedef struct _Eio_Model_Child_Add Eio_Model_Child_Add; +typedef struct _Eio_Model_Monitor_Data Eio_Model_Monitor_Data; + +struct _Eio_Model_Monitor_Data +{ + Ecore_Event_Handler *ecore_child_add_handler[3]; + Ecore_Event_Handler *ecore_child_del_handler[3]; + int mon_event_child_add[3]; /**< plus EIO_MONITOR_ERROR */ + int mon_event_child_del[3]; /**< plus EIO_MONITOR_ERROR */ +}; + +/** + * !! Warning: Do not change enum's order + * before checking _eio_model_constructor. + * @see Eina_Value_Struct_Member. + */ +enum { + EIO_MODEL_PROP_FILENAME = 0, + EIO_MODEL_PROP_PATH, + EIO_MODEL_PROP_MTIME, + EIO_MODEL_PROP_IS_DIR, + EIO_MODEL_PROP_IS_LNK, + EIO_MODEL_PROP_SIZE +}; + +struct _Eio_Model_Data +{ + Eo *obj; + char *path; + Eina_List *properties_list; + Eina_Value *properties; + Emodel_Load load; + int load_pending; + Eina_List *children_list; + /**< EIO data */ + Eio_File *file; + const Eina_Stat *stat; + Eio_Monitor *monitor; + Eio_Model_Monitor_Data mon; + int cb_count_child_add; /**< monitor reference counter for child add event */ + int cb_count_child_del; /**< monitor reference counter for child del event*/ + Eio_Filter_Direct_Cb filter_cb; + void *filter_userdata; +}; + +/* +struct _Eio_Model_Child_Add +{ + Eo *child; + Eio_Model_Data *priv; + char* fullpath; + char *name; +}; +*/ + +#endif diff --git a/src/lib/emodel/Emodel.h b/src/lib/emodel/Emodel.h new file mode 100644 index 0000000000..43c0b9c9b9 --- /dev/null +++ b/src/lib/emodel/Emodel.h @@ -0,0 +1,127 @@ +/** + @brief Emodel Library Public API Calls + These routines are used for MVC (Model View Controller) Library interaction. + */ +/** + * @page emodel_main Emodel + * + * @date 2014 (created) + * @section toc Table of Contents + * + * @li @ref emodel_main_intro + * @li @ref emodel_main_intro_example + * + * @section emodel_main_intro Introduction + * + * The Emodel(model) generic object system for Emodel View Controller. + * + * @section emodel_main_work How does Emodel work? + * + * The Model notifies Views and Controllers when there is a change in its state. + * The other way around is also true and the Model can be passive and be poolled + * for update rather than generating output representations. + * + * Concrete objects can implement functionalities by overriding Emodel's API, abstracting its complexities from + * applications that can keep focus on higher level implementation. + * + * Examples of concrete implementations that can make use Emodel: + * + * Filesystem and I/O operations; + * Database management; + * GUI forms, lists and trees. + * + * Application code tends to be small in number of lines, + * more simple and code readability is improved. + * + * Emodel use EO Events. Views and Controllers must register + * in events to be able to recieve notifications about state changes in Emodel. + * Some of currently available events are: + * + * EMODEL_EVENT_LOAD_STATUS + * EMODEL_EVENT_PROPERTIES_CHANGED + * EMODEL_EVENT_CHILD_ADDED + * EMODEL_EVENT_CHILD_REMOVED + * EMODEL_EVENT_CHILDREN_COUNT_CHANGED + * + * Example code using Emodel_Eio that returns the number of files in '/tmp' directory: + * + * @code + * static Eina_Bool + * _children_count_cb(void *data EINA_UNUSED, Eo *obj EINA_UNUSED, const Eo_Event_Description *desc EINA_UNUSED, void *event_info) + * { + * size_t *len = event_info; + * fprintf(stdout, "Children count len=%lu\n", *len); + * return EINA_TRUE; + * } + * + * int + * main(int argc, const char **argv) + * { + * size_t total; + * Eo *model; + * if(!ecore_init()) + * { + * fprintf(stderr, "ERROR: Cannot init Ecore!\n"); + * return 1; + * } + * if(!eio_init()) + * { + * fprintf(stderr, "ERROR: Cannot init Eio!\n"); + * return 1; + * } + * + * model = eo_add_custom(EIO_MODEL_CLASS, NULL, eio_model_constructor("/tmp")); + * eo_do(model, eo_event_callback_add(EMODEL_EVENT_CHILDREN_COUNT_CHANGED, _children_count_cb, NULL)); + * eo_do(model, emodel_children_count_get(&total)); + * fprintf(stdout, "total=%lu\n", total); + * + * ecore_main_loop_begin(); + * eo_unref(model); + * eio_shutdown(); + * ecore_shutdown(); + * return 0; + * } + * @endcode + * + * In previous example the concrete Emodel_Eio counts, asynchronously, the number of files in given directory, + * emodel_children_count_get() returns into 'total' pointer the last known number of children. In the meantime + * when background count is finished _children_count_cb() is invoked receiving the number of files as event_info data. + * This is achieved by registering the Model as EMODEL_EVENT_CHILDREN_COUNT_CHANGED event listener and every time + * the count (number of children) changes, the event is disptached to listeners. + * + * The principles may remain the same for different events and the logic remains. + * + * @li @ref emodel_main_intro_example + * + * @include emodel_test_file.c + * + * Recommended reading: + * + * @li @ref Eo, where you'll understand how Eo Events work. + * @li @ref Eio, where you'll find EFL Eio implementation and interfaces. + * @li @ref Emodel_Eio, the concrete EIO implementation using both Emodel and Eio. + * @li @ref Ecore, You'll get more information about I/O filesystem events. + * + * @defgroup Emodel + * + * @addtogroup Emodel + * @{ + */ + +#ifndef _EMODEL_H +#define _EMODEL_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#ifdef __cplusplus +} +#endif +#endif //_EMODEL_H diff --git a/src/lib/emodel/Emodel_Common.h b/src/lib/emodel/Emodel_Common.h new file mode 100644 index 0000000000..d457c48afd --- /dev/null +++ b/src/lib/emodel/Emodel_Common.h @@ -0,0 +1,106 @@ +#ifndef _EMODEL_COMMON_H +#define _EMODEL_COMMON_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @enum _Emodel_Load_Status + * XXX/TODO/FIXME: Remove this enum (and possibly other data) from here + * as soon as eolian translates these data types in .eo's. + */ +enum _Emodel_Load_Status + { + EMODEL_LOAD_STATUS_ERROR = 0, + EMODEL_LOAD_STATUS_LOADING_PROPERTIES = (1 << 0), + EMODEL_LOAD_STATUS_LOADING_CHILDREN = (1 << 1), + EMODEL_LOAD_STATUS_LOADING = (1 << 0) | (1 << 1), + + EMODEL_LOAD_STATUS_LOADED_PROPERTIES = (1 << 2), + EMODEL_LOAD_STATUS_LOADED_CHILDREN = (1 << 3), + EMODEL_LOAD_STATUS_LOADED = (1 << 2) | (1 << 3), + + EMODEL_LOAD_STATUS_UNLOADING = (1 << 4), + EMODEL_LOAD_STATUS_UNLOADED = (1 << 5) + }; +/** + * @typedef Emodel_Load_Status + */ +typedef enum _Emodel_Load_Status Emodel_Load_Status; + +/** + * @struct _Emodel_Load + * Structure to hold Emodel_Load_Status enum + * (and possible other data) to avoid ABI break. + */ +struct _Emodel_Load + { + Emodel_Load_Status status; + /* add more data below here if necessary */ + }; + +/** + * @typedef Emodel_Load + */ +typedef struct _Emodel_Load Emodel_Load; + +/** + * @struct _Emodel_Property_Pair + */ +struct _Emodel_Property_Pair +{ + Eina_Value value; /**< the property value */ + Eina_Stringshare *property; /**< the property name */ +}; + +/** + * @typedef Emodel_Property_Pair + */ +typedef struct _Emodel_Property_Pair Emodel_Property_Pair; + +/** + * @struct _Emodel_Property_Event + */ +struct _Emodel_Property_Event +{ + Eina_List *changed_properties; /**< the property value */ + Eina_List *invalidated_properties; /**< the property name */ +}; + +/** + * @typedef Emodel_Property_Event + */ +typedef struct _Emodel_Property_Event Emodel_Property_Event; + +/** + * @struct _Emodel_Children_Event + * Every time a child id added the event + * EMODEL_EVENT_CHILD_ADDED is dispatched + * passing along this structure. + */ +struct _Emodel_Children_Event +{ + Eo *child; /**< child, for child_add */ + /** + * index is a hint and is intended + * to provide a way for applications + * to control/know children relative + * positions through listings. + * + * NOTE: If listing is performed asynchronously + * exact order may not be guaranteed. + */ + unsigned int index; +}; + +/** + * @struct Emodel_Children_Event + */ +typedef struct _Emodel_Children_Event Emodel_Children_Event; + + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/lib/emodel/emodel.c b/src/lib/emodel/emodel.c new file mode 100644 index 0000000000..c8df075bc5 --- /dev/null +++ b/src/lib/emodel/emodel.c @@ -0,0 +1,6 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "Emodel.h" +#include "emodel.eo.c" diff --git a/src/lib/emodel/emodel.eo b/src/lib/emodel/emodel.eo new file mode 100644 index 0000000000..39fccf239c --- /dev/null +++ b/src/lib/emodel/emodel.eo @@ -0,0 +1,326 @@ +/* + * type Emodel_Load_Status: enum _Emodel_Load_Status + * { + * EMODEL_LOAD_STATUS_ERROR = 0, /*@ Error in Load Model * + * EMODEL_LOAD_STATUS_LOADING_PROPERTIES = (1 << 0), /*@ properties load in progress * + * EMODEL_LOAD_STATUS_LOADING_CHILDREN = (1 << 1), /*@ children load in progress * + * EMODEL_LOAD_STATUS_LOADING = (1 << 0) | (1 << 1), /*@ children and properties load in progress * + * + * EMODEL_LOAD_STATUS_LOADED_PROPERTIES = (1 << 2), /*@ Model as ready to fetch properties * + * EMODEL_LOAD_STATUS_LOADED_CHILDREN = (1 << 3), /*@ Model as ready to fetch children * + * EMODEL_LOAD_STATUS_LOADED = (1 << 2) | (1 << 3), /*@ Model as ready to fetch properties and children * + * + * EMODEL_LOAD_STATUS_UNLOADING = (1 << 4), /*@ Model Unload in progress * + * EMODEL_LOAD_STATUS_UNLOADED = (1 << 5) /*@ Model Unloaded * + * } + * + * type Emodel_Property_Pair: struct _Emodel_Property_Pair + * { + * value: Eina_Value; /*@ the new property value * + * property: const(char)*; /*@ the property name that has been changed * + * } + * + * type Emodel_Property_Event: struct _Emodel_Property_Event + * { + * changed_properties: Eina_List* ; /*@ List of changed properties * + * invalidated_properties: Eina_List* ; /*@ Removed properties identified by name * + * } + */ + +interface Emodel () +{ + legacy_prefix: null; + properties { + load_status { + get { + /*@ + Get a load emodel current status. + + @return: @c Emodel_Load_Status + + By convention this means get the current model status. + Possible values are defined Emodel_Load_Status enumerator. + + @see Emodel_Load_Status + @see emodel_load + + @since 1.11 */ + return: Emodel_Load_Status; + } + } + properties_list { + get { + /*@ + Get properties list from model. + + @return: @c Emodel_Load_Status + + properties_list_get is due to provide callers a way the fetch the current + properties implemented/used by the model. + The event EMODEL_EVENT_PROPERTIES_CHANGE will be raised to notify listeners + of any modifications in the properties list. + + @see EMODEL_EVENT_PROPERTIES_CHANGE + @since 1.11 */ + + return: Emodel_Load_Status; + } + values { + const(list*) properties_list; /*@ list of current properties */ + } + } + property { + set { + /*@ + Set a property value of a given property name. + + @return: @c EINA_TRUE, on success, @c EINA_FALSE in readonly property or error + + The caller must ensure to call at least emodel_prop_list before being + able to see/set properties. + This function sets a new property value into given property name. Once + the operation is completed the concrete implementation should raise + EMODEL_EVENT_PROPERTIES_CHANGE event in order to notify listeners of the + new value of the property. + + If the model doesn't have the property then there are two possibilities, + either raise an error or create the new property in model + + @see emodel_property_get + @see EMODEL_EVENT_PROPERTIES_CHANGE + @since 1.11 */ + + return: Emodel_Load_Status; + } + get { + /*@ + Retrieve the value of a given property name. + + @return: @c Load Status, on success, @c EMODEL_LOAD_STATUS_ERROR otherwise + + property_get will only be available when load status is equal to + EMODEL_LOAD_STATUS_LOADED. + + At this point the caller is free to get values from properties. + The event EMODEL_EVENT_PROPERTIES_CHANGE may be raised to notify + listeners of the property/value. + + @see emodel_properties_list_get + @see EMODEL_EVENT_PROPERTIES_CHANGE + + @since 1.11 */ + return: Emodel_Load_Status; + } + keys { + const(char)* property; /*@ Property name */ + } + values { + Eina_Value value; /*@ New value */ + } + } + children_slice { + get { + /*@ + Get children slice OR full range. + + @return: @c Emodel_Load_Status. See below for more info. + + Before being able to get the children list the model status must be + on loaded status (EMODEL_LOAD_STATUS_LOADED). + However there may be circunstancies where the model could be + in a different state, in such cases it is advisable + to simply return: its current state, which will be + of course, different than @c EMODEL_LOAD_STATUS_LOADED_CHILDREN. + When children accessor is return:ed as NULL one should then + test the current load status return:ed by @children_slice_get + in order to check against an empty list or real error. + + children_slice_get behaves in two different ways, it may provide + the slice if both @c start AND @c count are non-zero OR full range otherwise. + + The return:ed Eina_Accessor must be freed when it is no longer needed and + eo_unref() must be invoked for children if caller wants a copy. + + Since 'slice' is a range, for example if we have 20 childs a slice could be + the range from 3(start) to 4(count), see: + child 0 [no] + child 1 [no] + child 2 [yes] + child 3 [yes] + child 4 [yes] + child 5 [yes] + child 6 [no] + child 7 [no] + + Optionally the user can call children_count_get to know + the number of children so a valid range can be known in advance. + + Below are examples of both usage types: slices and full ranges. + @code + + // Returns full list + eo_do(obj, emodel_children_slice_get(0, 0, &children_accessor)); + + // Returns 5 items, counting from item #5 + eo_do(obj, emodel_children_slice_get(5, 5, &children_accessor)); + + @endcode + + @see emodel_children_get + @see emodel_children_count_get + @see emodel_load + @see emodel_load_status_get + @since 1.11 */ + + return: Emodel_Load_Status; + } + keys { + unsigned start; /*@ Range begin - start from here. If start and count are 0 slice is ignored.*/ + unsigned count; /*@ Range size. If count and start are 0 slice is ignored.*/ + } + values { + accessor* children_accessor; + } + } + children_count { + get { + /*@ + Get children count. + + @return: @c EINA_TRUE, on success, @c EINA_FALSE otherwise + + When emodel_load is completed emodel_coildren_count_get can be use + to get the number of children. children_count_get can also be used + before calling children_slice_get so a valid range is known. + Event EMODEL_CHILDREN_COUNT_CHANGED is emitted when count is finished. + + @see emodel_children_get + @see emodel_children_slice_get + @see emodel_load + @see emodel_load_status_get + @since 1.11 */ + + return: Emodel_Load_Status; + } + values { + unsigned children_count; + } + } + } + methods { + load { + /*@ + Load emodel. + + By convention this means loading data from an external source and populating + the models properties and children with it. For example in the case of file + system backed model, this means opening the relevant files and reading the + data from them(creating the properties and children from it). + the model emit EMODEL_EVENT_LOAD_STATUS after end with Emodel_Load_Status + @warning This convention should be followed, but no guarantees of behaviour + by user defined types can be given. + + Alternatively is possible to use properties_load to load only properties + and children_load to load only children. If emodel_load is called then + calling properties_load and/or children_load is not necessary. + + @see Emodel_Load_Status + @see emodel_properties_load + @see emodel_children_load + @see emodel_unload + @see emodel_load_status_get + + @since 1.11 */ + } + unload { + /*@ + Unload emodel. + + By convention this means releasing data received/read from an external source. For + example of a database backed model this might mean releasing the iterator for + the currently loaded data or deleting a temporary table. + the model emit EMODEL_EVENT_LOAD_STATUS after end with model load status + @warning This convention should be followed, but no guarantees of behaviour + by user defined types can be given. + + @see Emodel_Load_Status + @see emodel_load + @see emodel_load_status_get + + @since 1.11 */ + } + properties_load { + /*@ + Properties emodel load. + + By convention this means loading data from an external source and populating + the models properties only. This method is a subset of emodel_load, meaning that + it won't load children, it is a hint. + For loadind both properties and children use emodel_load + instead. + + @see emodel_load + + @since 1.11 */ + } + children_load { + /*@ + Children emodel load. + + By convention this means loading data from an external source and populating + the models children only. This method is a subset of emodel_load, meaning that + it won't load properties. For loadind both properties and children use emodel_load + instead. + + @see emodel_load + + @since 1.11 */ + } + child_add { + /*@ + Add a new child. + + @return: @c Emodel* on success, @c NULL otherwise + + Add a new child, possibly dummy, depending on the implementation, + of a internal keeping. When the child is effectively + added the event EMODEL_EVENT_CHILD_ADD is then raised and the new child + is kept along with other children. + + @see EMODEL_EVENT_CHILD_ADD + @see load_status_get + + @since 1.11 */ + + return: Eo *; + } + child_del { + /*@ + Remove a child. + + @return: @c Emodel_Load_Status on success, @c EMODEL_LOAD_STATUS_ERROR otherwise. + + Remove a child of a internal keeping. When the child is effectively + removed the event EMODEL_EVENT_CHILD_REMOVED is then raised to give a + chance for listeners to perform any cleanup and/or update references. + + @see EMODEL_EVENT_CHILD_REMOVED + @since 1.11 */ + + return: Emodel_Load_Status; + + params { + @in Eo* child; /*@ Child to be removed */ + } + } + } + + events { + load,status: Emodel_Load_Status; /*@ Event dispatch when load status changes */ + properties,changed: Emodel_Properties_Evt; /*@ Event dispatched when properties list is available. */ + child,added; /*@ Event dispatched when new child is added. */ + child,removed; /*@ Event dispatched when child is removed. */ + children,count,changed; /*@ Event dispatched when children count is finished. */ + } +} + diff --git a/src/tests/emodel/emodel_suite.c b/src/tests/emodel/emodel_suite.c new file mode 100644 index 0000000000..33b61e0e34 --- /dev/null +++ b/src/tests/emodel/emodel_suite.c @@ -0,0 +1,138 @@ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include +#include + +#include + +void emodel_test_file(TCase* tc); +void emodel_test_monitor_add(TCase* tc); + +typedef struct _Emodel_Test_Case Emodel_Test_Case; +struct _Emodel_Test_Case +{ + const char *test_case; + void (*build)(TCase *tc); +}; + +static const Emodel_Test_Case etc[] = { + { "File", emodel_test_file }, + { "Monitor Add", emodel_test_monitor_add }, + { NULL, NULL } +}; + +static void +_list_tests(void) +{ + const Emodel_Test_Case *itr = etc; + fputs("Available Test Cases:\n", stderr); + for (; itr->test_case; itr++) + fprintf(stderr, "\t%s\n", itr->test_case); +} + +static Eina_Bool +_use_test(int argc, const char **argv, const char *test_case) +{ + if (argc < 1) + return 1; + + for (; argc > 0; argc--, argv++) + if (strcmp(test_case, *argv) == 0) + return 1; + + return 0; +} + +Suite * +emodel_build_suite(int argc, const char **argv) +{ + TCase *tc; + Suite *s; + int i; + + s = suite_create("Emodel"); + + for (i = 0; etc[i].test_case; ++i) + { + if (!_use_test(argc, argv, etc[i].test_case)) + continue; + + tc = tcase_create(etc[i].test_case); + tcase_set_timeout(tc, 0); + + etc[i].build(tc); + suite_add_tcase(s, tc); + } + + return s; +} + +/* FIXME this is a copy from eina_test_mempool + * we should remove the duplication + */ +static Eina_Array *_modules; +static void _mempool_init(void) +{ + eina_init(); + /* force modules to be loaded in case they are not installed */ + _modules = eina_module_list_get(NULL, + PACKAGE_BUILD_DIR "/src/modules", + EINA_TRUE, + NULL, + NULL); + eina_module_list_load(_modules); +} + +static void _mempool_shutdown(void) +{ + eina_module_list_free(_modules); + if (_modules) + eina_array_free(_modules); + /* TODO delete the list */ + eina_shutdown(); +} + +int +main(int argc, char **argv) +{ + Suite *s; + SRunner *sr; + int i, failed_count; + + for (i = 1; i < argc; i++) + if ((strcmp(argv[i], "-h") == 0) || + (strcmp(argv[i], "--help") == 0)) + { + fprintf(stderr, "Usage:\n\t%s [test_case1 .. [test_caseN]]\n", + argv[0]); + _list_tests(); + return 0; + } + else if ((strcmp(argv[i], "-l") == 0) || + (strcmp(argv[i], "--list") == 0)) + { + _list_tests(); + return 0; + } + + putenv("EFL_RUN_IN_TREE=1"); + + s = emodel_build_suite(argc - 1, (const char **)argv + 1); + sr = srunner_create(s); + + srunner_set_xml(sr, TESTS_BUILD_DIR "/check-results.xml"); + + _mempool_init(); + + srunner_run_all(sr, CK_ENV); + failed_count = srunner_ntests_failed(sr); + srunner_free(sr); + + _mempool_shutdown(); + + return (failed_count == 0) ? 0 : 255; +} diff --git a/src/tests/emodel/emodel_test_file.c b/src/tests/emodel/emodel_test_file.c new file mode 100644 index 0000000000..029aa2e459 --- /dev/null +++ b/src/tests/emodel/emodel_test_file.c @@ -0,0 +1,273 @@ +//Compile with: +// gcc -o emodel_test_file emodel_test_file.c `pkg-config --cflags --libs emodel` +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include +#include + +#include + +#define EMODEL_TEST_FILENAME_PATH "/tmp" +#define EMODEL_MAX_TEST_CHILDS 16 + +/** + * The following test works however + * it is going to rename (move) the original directory to + * new one so '/tmp' as root dir doesn't work , you'll need to use + * '/tmp/some_other_dir' as root instead. + */ +//#define _RUN_LOCAL_TEST + +struct reqs_t { + /* property change */ + int changed_is_dir; + int changed_is_lnk; + int changed_size; + int changed_mtime; + int changed_icon; + + /* properties list */ + int proplist_filename; + int proplist_path; + int proplist_icon; + int proplist_mtime; + int proplist_is_dir; + int proplist_is_lnk; + int proplist_size; + + /* misc tests for data or propeties */ + int properties; + int children; + int child_add; + int child_del; +}; + +static struct reqs_t reqs; +static Ecore_Event_Handler *handler; + +static Eina_Bool + exit_func(void *data EINA_UNUSED, int ev_type EINA_UNUSED, void *ev) + { + Ecore_Event_Signal_Exit *e; + + e = (Ecore_Event_Signal_Exit *)ev; + if (e->interrupt) fprintf(stdout, "Exit: interrupt\n"); + else if (e->quit) fprintf(stdout, "Exit: quit\n"); + else if (e->terminate) fprintf(stdout, "Exit: terminate\n"); + ecore_main_loop_quit(); + return ECORE_CALLBACK_CANCEL; + } + +static Eina_Bool +_load_status_cb(void *data EINA_UNUSED, Eo *obj, const Eo_Event_Description *desc EINA_UNUSED, void *event_info) +{ + Emodel_Load *st = event_info; + printf("Load CHANGE\n"); + + if (st->status & EMODEL_LOAD_STATUS_LOADED_CHILDREN) + printf("Children is Loaded\n"); + + if (st->status & EMODEL_LOAD_STATUS_LOADED_PROPERTIES) + printf("Properties is Loaded\n"); + + if ((st->status & EMODEL_LOAD_STATUS_LOADED) == EMODEL_LOAD_STATUS_LOADED) + { + Eina_Accessor *accessor; + Eina_Value value_prop; + Eo *child; + Emodel_Load_Status status; + unsigned int total, i; + char *str; + + printf("Model is Loaded\n"); + eo_do(obj, status = emodel_property_get("filename", &value_prop)); + str = eina_value_to_string(&value_prop); + printf("emodel_loaded filename %s, status=%d\n", str, status); + eina_value_flush(&value_prop); + free(str); + + eo_do(obj, status = emodel_property_get("size", &value_prop)); + str = eina_value_to_string(&value_prop); + printf("emodel_loaded size %s, status=%d\n", str, status); + eina_value_flush(&value_prop); + free(str); + + eo_do(obj, status = emodel_property_get("mtime", &value_prop)); + str = eina_value_to_string(&value_prop); + printf("emodel_loaded mtime %s, status=%d\n", str, status); + eina_value_flush(&value_prop); + free(str); + + eo_do(obj, emodel_children_count_get(&total)); + printf("emodel_test count %d\n", (int)total); + + /**< get full list */ + eo_do(obj, status = emodel_children_slice_get(0 ,0 ,(Eina_Accessor **)&accessor)); + EINA_ACCESSOR_FOREACH(accessor, i, child) + { + //XXX: check if there is memleak + eo_do(child, status = emodel_property_get("filename", &value_prop)); + str = eina_value_to_string(&value_prop); + printf("(full) %d emodel_children_get filename %s\n", i, str); + eina_value_flush(&value_prop); + free(str); + } + + i = 0; + eina_accessor_free(accessor); + eo_do(obj, status = emodel_children_slice_get(5 ,5 ,(Eina_Accessor **)&accessor)); + + EINA_ACCESSOR_FOREACH(accessor, i, child) + { + //XXX: check if there is memleak + eo_do(child, status = emodel_property_get("filename", &value_prop)); + str = eina_value_to_string(&value_prop); + printf("(slice) %d emodel_chidlren_property_set filename %s\n", i, str); + eina_value_flush(&value_prop); + free(str); + eo_unref(child); + } + eina_accessor_free(accessor); + ecore_main_loop_quit(); + } + return EINA_TRUE; +} + +static Eina_Bool +_properties_cb(void *data EINA_UNUSED, Eo *obj EINA_UNUSED, const Eo_Event_Description *desc EINA_UNUSED, void *event_info) +{ + const Emodel_Property_Event *evt = (Emodel_Property_Event *)event_info; + Emodel_Property_Pair *pair = NULL; + Eina_List *l = NULL; + + EINA_LIST_FOREACH(evt->changed_properties, l, pair) + { + char *str; + str = eina_value_to_string(&pair->value); + fprintf(stdout, "Received changed property=%s, value=%s\n", + pair->property, str); + free(str); + if(!strcmp(pair->property, "is_dir")) + reqs.changed_is_dir = 1; + if(!strcmp(pair->property, "is_lnk")) + reqs.changed_is_lnk = 1; + if(!strcmp(pair->property, "size")) + reqs.changed_size = 1; + if(!strcmp(pair->property, "mtime")) + reqs.changed_mtime = 1; + if(!strcmp(pair->property, "icon")) + reqs.changed_icon = 1; + } + + reqs.properties = 1; + return EINA_TRUE; +} + +static Eina_Bool +_children_count_cb(void *data EINA_UNUSED, Eo *obj EINA_UNUSED, const Eo_Event_Description *desc EINA_UNUSED, void *event_info) +{ + unsigned int *len = (unsigned int *)event_info; + unsigned int total; + + fprintf(stdout, "Children count number=%d\n", *len); + reqs.children = *len; + + eo_do(obj, emodel_children_count_get(&total)); + fprintf(stdout, "New total children count number=%d\n", *len); + + return EINA_TRUE; +} + +START_TEST(emodel_test_test_file) +{ + Eo *filemodel = NULL; + Eina_Value value_prop; + Emodel_Load_Status status; +#ifdef _RUN_LOCAL_TEST + Eina_Value nameset_value; +#endif + Eina_List *properties_list; + Eina_List *l; + char *str; + int i; + + memset(&reqs, -1, sizeof(struct reqs_t)); + + fail_if(!eina_init(), "ERROR: Cannot init Eina!\n"); + fail_if(!ecore_init(), "ERROR: Cannot init Ecore!\n"); + fail_if(!eio_init(), "ERROR: Cannot init EIO!\n"); + + filemodel = eo_add(EIO_MODEL_CLASS, NULL, eio_model_path_set(EMODEL_TEST_FILENAME_PATH)); + fail_if(!filemodel, "ERROR: Cannot init model!\n"); + + eo_do(filemodel, eo_event_callback_add(EMODEL_EVENT_LOAD_STATUS, _load_status_cb, NULL)); + eo_do(filemodel, eo_event_callback_add(EMODEL_EVENT_PROPERTIES_CHANGED, _properties_cb, NULL)); + eo_do(filemodel, eo_event_callback_add(EMODEL_EVENT_CHILDREN_COUNT_CHANGED, _children_count_cb, NULL)); + + eo_do(filemodel, emodel_load()); + + handler = ecore_event_handler_add(ECORE_EVENT_SIGNAL_EXIT, exit_func, NULL); + + eina_value_setup(&value_prop, EINA_VALUE_TYPE_STRING); + + eo_do(filemodel, status = emodel_property_get("filename", &value_prop)); + str = eina_value_to_string(&value_prop); + printf("emodel_test filename %s, load status %d\n", str, status); + + eina_value_flush(&value_prop); + free(str); + + i = 0; + eo_do(filemodel, emodel_properties_list_get(&properties_list)); + EINA_LIST_FOREACH((Eina_List *)properties_list, l, str) + { + fprintf(stdout, "Returned property list %d: %s\n", i++, str); + if(!strcmp(str, "filename")) + reqs.proplist_filename = 1; + else if(!strcmp(str, "path")) + reqs.proplist_path = 1; + else if(!strcmp(str, "icon")) + reqs.proplist_icon = 1; + else if(!strcmp(str, "mtime")) + reqs.proplist_mtime = 1; + else if(!strcmp(str, "is_dir")) + reqs.proplist_is_dir = 1; + else if(!strcmp(str, "is_lnk")) + reqs.proplist_is_lnk = 1; + else if(!strcmp(str, "size")) + reqs.proplist_size = 1; + } + + ecore_main_loop_begin(); + +#ifdef _RUN_LOCAL_TEST + eina_value_setup(&nameset_value, EINA_VALUE_TYPE_STRING); + eina_value_setup(&value_prop, EINA_VALUE_TYPE_STRING); + eina_value_set(&nameset_value, "/tmp/emodel_test"); + eo_do(filemodel, emodel_property_set("path", nameset_value)); + eina_value_flush(&nameset_value); + //emodel_property_get("path", &value_prop); + eo_do(filemodel, status = emodel_property_get("path", &value_prop)); + eina_value_flush(&value_prop); +#endif + + sleep(1); /**< EIO is asynchrounous so I must give some time for deletions to execute */ + eo_unref(filemodel); + ecore_shutdown(); + eina_shutdown(); + eio_shutdown(); +} +END_TEST + +void +emodel_test_file(TCase *tc) +{ + /* tcase_add_test(tc, emodel_test_test_file); */ +} + diff --git a/src/tests/emodel/emodel_test_monitor_add.c b/src/tests/emodel/emodel_test_monitor_add.c new file mode 100644 index 0000000000..166b3847ee --- /dev/null +++ b/src/tests/emodel/emodel_test_monitor_add.c @@ -0,0 +1,105 @@ +//Compile with: +// gcc -o emodel_test_file emodel_test_file.c `pkg-config --cflags --libs emodel` +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include +#include + +#include + +#define EMODEL_TEST_FILENAME_PATH "/tmp" + +Eina_Bool children_added = EINA_FALSE; + +static Eina_Bool +_children_added_cb(void *data EINA_UNUSED, Eo *obj EINA_UNUSED, const Eo_Event_Description *desc EINA_UNUSED, void *event_info) +{ + Emodel_Children_Event* evt = event_info; + Eo* child = evt->child; + Eina_Value value_prop; + const char* str; + + eo_do(child, emodel_property_get("filename", &value_prop)); + str = eina_value_to_string(&value_prop); + fprintf(stderr, "new children filename %s\n", str); + if(strcmp(str, "test_file_monitor_add") == 0) + { + fprintf(stderr, "is child that we want\n"); + children_added = EINA_TRUE; + eo_do(obj, emodel_child_del(child)); + ecore_main_loop_quit(); + } + eina_value_flush(&value_prop); + return EINA_TRUE; +} + +static Eina_Bool +_children_count_cb(void *data EINA_UNUSED, Eo *obj, const Eo_Event_Description *desc EINA_UNUSED, void *event_info) +{ + unsigned int *len = event_info; + Eina_Accessor *accessor; + Emodel_Load_Status status; + Eo *child; + unsigned int i = 0; + + fprintf(stderr, "Children count number=%d\n", *len); + + /**< get full list */ + eo_do(obj, status = emodel_children_slice_get(0 ,0 ,(Eina_Accessor **)&accessor)); + if(accessor != NULL) + { + EINA_ACCESSOR_FOREACH(accessor, i, child) {} + fprintf(stdout, "Got %d childs from Accessor. status=%d\n", i, status); + } + + fclose(fopen(EMODEL_TEST_FILENAME_PATH "/test_file_monitor_add", "w+")); + + return EINA_TRUE; +} + +START_TEST(emodel_test_test_monitor_add) +{ + Eo *filemodel = NULL; + + fprintf(stderr, "emodel_test_test_monitor_add\n"); + + fail_if(!eina_init(), "ERROR: Cannot init Eina!\n"); + fail_if(!ecore_init(), "ERROR: Cannot init Ecore!\n"); + fail_if(!eio_init(), "ERROR: Cannot init EIO!\n"); + + filemodel = eo_add(EIO_MODEL_CLASS, NULL, eio_model_path_set(EMODEL_TEST_FILENAME_PATH)); + fail_if(!filemodel, "ERROR: Cannot init model!\n"); + + eo_do(filemodel, eo_event_callback_add(EMODEL_EVENT_CHILDREN_COUNT_CHANGED, _children_count_cb, NULL)); + eo_do(filemodel, eo_event_callback_add(EMODEL_EVENT_CHILD_ADDED, _children_added_cb, NULL)); + + eo_do(filemodel, emodel_load()); + + ecore_main_loop_begin(); + + sleep(1); /**< EIO is asynchrounous so I must give some time for deletions to execute */ + + ecore_main_loop_iterate(); /**< Give time to unlink file */ + + eo_unref(filemodel); + + eio_shutdown(); + ecore_shutdown(); + eina_shutdown(); + + fail_if(!children_added); +} +END_TEST + +void +emodel_test_monitor_add(TCase *tc) +{ + tcase_add_test(tc, emodel_test_test_monitor_add); +} +