summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLauro Moura <lauromoura@expertisesolutions.com.br>2019-08-05 10:17:52 -0400
committerMike Blumenkrantz <zmike@samsung.com>2019-08-05 10:18:18 -0400
commit40def3eac914138189163a895527705a1ffefcfd (patch)
treee77fc891713de50ca312b080474260d34d7d36df
parent7c72f101532d61b00cd483b89ef86830526a82ba (diff)
efl-mono: Add Model manual implementation to C# and MVVM factories
Summary: Depends on D9273, D9270 Test Plan: Run added testcases. Reviewers: cedric, bu5hm4n, zmike, SanghyeonLee, felipealmeida, segfaultxavi Reviewed By: cedric Subscribers: cedric Tags: #expertise_solutions, #efl_language_bindings Differential Revision: https://phab.enlightenment.org/D8080
-rw-r--r--src/bin/eolian_mono/eolian/mono/function_definition.hh53
-rw-r--r--src/bin/eolian_mono/eolian/mono/klass.hh10
-rw-r--r--src/bindings/mono/efl_mono/Bind.cs36
-rw-r--r--src/bindings/mono/efl_mono/Factory.cs30
-rw-r--r--src/bindings/mono/efl_mono/GenericModel.cs174
-rw-r--r--src/bindings/mono/efl_mono/UserModel.cs104
-rw-r--r--src/bindings/mono/efl_mono/meson.build55
-rw-r--r--src/bindings/mono/eo_mono/FunctionWrapper.cs2
-rw-r--r--src/bindings/mono/meson.build7
-rw-r--r--src/lib/efl/interfaces/efl_model.eo2
-rw-r--r--src/lib/efl_mono/efl_mono_model_internal.c229
-rw-r--r--src/lib/efl_mono/efl_mono_model_internal.eo19
-rw-r--r--src/lib/efl_mono/efl_mono_model_internal_child.eo10
-rw-r--r--src/tests/efl_mono/Main.cs2
-rw-r--r--src/tests/efl_mono/Model.cs83
-rw-r--r--src/tests/efl_mono/meson.build3
16 files changed, 807 insertions, 12 deletions
diff --git a/src/bin/eolian_mono/eolian/mono/function_definition.hh b/src/bin/eolian_mono/eolian/mono/function_definition.hh
index 8c43008c53..cf85f6844d 100644
--- a/src/bin/eolian_mono/eolian/mono/function_definition.hh
+++ b/src/bin/eolian_mono/eolian/mono/function_definition.hh
@@ -223,6 +223,52 @@ struct native_function_definition_parameterized
223 } 223 }
224} const native_function_definition; 224} const native_function_definition;
225 225
226struct property_extension_method_definition_generator
227{
228 template<typename OutputIterator, typename Context>
229 bool generate(OutputIterator sink, attributes::property_def const& property, Context context) const
230 {
231 if (blacklist::is_property_blacklisted(property, context))
232 return true;
233
234 auto options = efl::eolian::grammar::context_find_tag<options_context>(context);
235
236 if (!options.want_beta)
237 return true; // Bindable is a beta feature for now.
238
239 auto get_params = property.getter.is_engaged() ? property.getter->parameters.size() : 0;
240 auto set_params = property.setter.is_engaged() ? property.setter->parameters.size() : 0;
241
242 std::string managed_name = name_helpers::property_managed_name(property);
243
244 if (get_params > 0 || set_params > 1)
245 return true;
246
247 std::string dir_mod;
248 if (property.setter.is_engaged())
249 dir_mod = direction_modifier(property.setter->parameters[0]);
250
251 if (property.setter.is_engaged())
252 {
253 attributes::type_def prop_type = property.setter->parameters[0].type;
254 if (!as_generator("public static Efl.Bindable<" << type(true) << "> " << managed_name << "<T>(this Efl.Ui.ItemFactory<T> fac) where T : " << name_helpers::klass_full_concrete_or_interface_name(cls) << " {\n"
255 << scope_tab << scope_tab << "return new Efl.Bindable<" << type(true) << ">(\"" << property.name << "\", fac);\n"
256 << scope_tab << "}\n"
257 ).generate(sink, std::make_tuple(prop_type, prop_type), context))
258 return false;
259 }
260
261 return true;
262 }
263
264 grammar::attributes::klass_def const& cls;
265};
266
267property_extension_method_definition_generator property_extension_method_definition (grammar::attributes::klass_def const& cls)
268{
269 return {cls};
270}
271
226struct property_wrapper_definition_generator 272struct property_wrapper_definition_generator
227{ 273{
228 template<typename OutputIterator, typename Context> 274 template<typename OutputIterator, typename Context>
@@ -345,6 +391,8 @@ struct is_eager_generator< ::eolian_mono::function_definition_generator> : std::
345template <> 391template <>
346struct is_eager_generator< ::eolian_mono::native_function_definition_generator> : std::true_type {}; 392struct is_eager_generator< ::eolian_mono::native_function_definition_generator> : std::true_type {};
347template <> 393template <>
394struct is_eager_generator< ::eolian_mono::property_extension_method_definition_generator> : std::true_type {};
395template <>
348struct is_eager_generator< ::eolian_mono::property_wrapper_definition_generator> : std::true_type {}; 396struct is_eager_generator< ::eolian_mono::property_wrapper_definition_generator> : std::true_type {};
349template <> 397template <>
350struct is_eager_generator< ::eolian_mono::property_wrapper_definition_parameterized> : std::true_type {}; 398struct is_eager_generator< ::eolian_mono::property_wrapper_definition_parameterized> : std::true_type {};
@@ -355,6 +403,8 @@ struct is_generator< ::eolian_mono::native_function_definition_generator> : std:
355template <> 403template <>
356struct is_generator< ::eolian_mono::function_definition_parameterized> : std::true_type {}; 404struct is_generator< ::eolian_mono::function_definition_parameterized> : std::true_type {};
357template <> 405template <>
406struct is_generator< ::eolian_mono::property_extension_method_definition_generator> : std::true_type {};
407template <>
358struct is_generator< ::eolian_mono::property_wrapper_definition_generator> : std::true_type {}; 408struct is_generator< ::eolian_mono::property_wrapper_definition_generator> : std::true_type {};
359template <> 409template <>
360struct is_generator< ::eolian_mono::property_wrapper_definition_parameterized> : std::true_type {}; 410struct is_generator< ::eolian_mono::property_wrapper_definition_parameterized> : std::true_type {};
@@ -370,6 +420,9 @@ template <>
370struct attributes_needed< ::eolian_mono::native_function_definition_generator> : std::integral_constant<int, 1> {}; 420struct attributes_needed< ::eolian_mono::native_function_definition_generator> : std::integral_constant<int, 1> {};
371 421
372template <> 422template <>
423struct attributes_needed< ::eolian_mono::property_extension_method_definition_generator> : std::integral_constant<int, 1> {};
424
425template <>
373struct attributes_needed< ::eolian_mono::property_wrapper_definition_generator> : std::integral_constant<int, 1> {}; 426struct attributes_needed< ::eolian_mono::property_wrapper_definition_generator> : std::integral_constant<int, 1> {};
374template <> 427template <>
375struct attributes_needed< ::eolian_mono::property_wrapper_definition_parameterized> : std::integral_constant<int, 1> {}; 428struct attributes_needed< ::eolian_mono::property_wrapper_definition_parameterized> : std::integral_constant<int, 1> {};
diff --git a/src/bin/eolian_mono/eolian/mono/klass.hh b/src/bin/eolian_mono/eolian/mono/klass.hh
index 80d4debc99..f118dea619 100644
--- a/src/bin/eolian_mono/eolian/mono/klass.hh
+++ b/src/bin/eolian_mono/eolian/mono/klass.hh
@@ -348,6 +348,16 @@ struct klass
348 if(!name_helpers::close_namespaces(sink, cls.namespaces, context)) 348 if(!name_helpers::close_namespaces(sink, cls.namespaces, context))
349 return false; 349 return false;
350 350
351 if(!as_generator
352 (lit("#pragma warning disable CS1591\n") // Disabling warnings as DocFx will hide these classes
353 <<"public static class " << (string % "_") << name_helpers::klass_inherit_name(cls)
354 << "_ExtensionMethods {\n"
355 << *((scope_tab << property_extension_method_definition(cls)) << "\n")
356 << "}\n"
357 << lit("#pragma warning restore CS1591\n"))
358 .generate(sink, std::make_tuple(cls.namespaces, cls.properties), context))
359 return false;
360
351 return true; 361 return true;
352 } 362 }
353 363
diff --git a/src/bindings/mono/efl_mono/Bind.cs b/src/bindings/mono/efl_mono/Bind.cs
new file mode 100644
index 0000000000..5a10f780f5
--- /dev/null
+++ b/src/bindings/mono/efl_mono/Bind.cs
@@ -0,0 +1,36 @@
1#if EFL_BETA
2
3using System;
4using System.Runtime.InteropServices;
5using System.Collections.Generic;
6using System.Linq;
7using System.ComponentModel;
8
9namespace Efl {
10
11/// <summary>Representas a bindable property as used by <see cref="Efl.Ui.ItemFactory&lt;T&gt;" /> instances.
12///
13/// <para>It is internally instantiated and returned by generated extension methods.</para>
14/// </summary>
15public class Bindable<T>
16{
17 /// <summary>Creates a new bindable property with the source name <c>name</c>.</summary>
18 public Bindable(string name, Efl.Ui.IPropertyBind binder)
19 {
20 this.name = name;
21 this.binder = binder;
22 }
23
24 /// <summary>Binds the model property <c>model_property</c> to the property <c>name</c> set in the constructor.</summary>
25 public void Bind(string model_property)
26 {
27 binder.PropertyBind(name, model_property);
28 }
29
30 string name;
31 Efl.Ui.IPropertyBind binder;
32}
33
34}
35
36#endif
diff --git a/src/bindings/mono/efl_mono/Factory.cs b/src/bindings/mono/efl_mono/Factory.cs
new file mode 100644
index 0000000000..d3c9c13e6d
--- /dev/null
+++ b/src/bindings/mono/efl_mono/Factory.cs
@@ -0,0 +1,30 @@
1#if EFL_BETA
2
3using System;
4using System.Runtime.InteropServices;
5using System.Collections.Generic;
6using System.Linq;
7using System.ComponentModel;
8
9namespace Efl { namespace Ui {
10
11/// <summary>Helper factory class. Makes use of C# extension methods for easier property binding.
12///
13/// <code>
14/// var factory = Efl.Ui.Factory&lt;Efl.Ui.Button&gt;();
15/// factory.Style().Bind("Name"); // The factory Style property is bound to the Name property for the given model.
16/// </code>
17///
18/// </summary>
19public class ItemFactory<T> : Efl.Ui.CachingFactory, IDisposable
20{
21 /// <summary>Creates a new factory.</summary>
22 public ItemFactory(Efl.Object parent = null)
23 : base (parent, typeof(T))
24 {
25 }
26}
27
28} }
29
30#endif
diff --git a/src/bindings/mono/efl_mono/GenericModel.cs b/src/bindings/mono/efl_mono/GenericModel.cs
new file mode 100644
index 0000000000..1bfa91e53d
--- /dev/null
+++ b/src/bindings/mono/efl_mono/GenericModel.cs
@@ -0,0 +1,174 @@
1using System;
2using System.Runtime.InteropServices;
3using System.Collections.Generic;
4using System.Linq;
5using System.ComponentModel;
6using Eina;
7
8#if EFL_BETA
9
10namespace Efl {
11
12/// <summary>Generic <see cref="Efl.IModel" /> implementation for MVVM models based on <see cref="Efl.UserModel&lt;T&gt;" /></summary>
13public class GenericModel<T> : Efl.Object, Efl.IModel, IDisposable
14{
15 private Efl.IModel model;
16
17 /// <summary>Creates a new model wrapping <c>model</c>.</summary>
18 public GenericModel (Efl.IModel model, Efl.Object parent = null) : base(parent)
19 {
20 this.model = model;
21 }
22
23 /// <summary>The list of properties available in the wrapped model.</summary>
24 public Eina.Iterator< System.String> Properties
25 {
26 get { return GetProperties(); }
27 }
28
29 /// <summary>The number of children in the wrapped model.</summary>
30 public uint ChildrenCount
31 {
32 get { return GetChildrenCount(); }
33 }
34
35 /// <summary>The list of properties available in the wrapped model.</summary>
36 public Eina.Iterator<System.String> GetProperties()
37 {
38 return model.GetProperties();
39 }
40
41 /// <summary>Gets the value of the given property in the wrapped model.</summary>
42 public Eina.Value GetProperty( System.String property)
43 {
44 return model.GetProperty(property);
45 }
46
47 /// <summary>Sets the value of the given property in the given model.</summary>
48 public Eina.Future SetProperty( System.String property, Eina.Value value)
49 {
50 return model.SetProperty(property, value);
51 }
52
53 /// <summary>Returns the number of children in the wrapped model.</summary>
54 public uint GetChildrenCount()
55 {
56 return model.GetChildrenCount();
57 }
58
59 /// <summary>Returns an <see cref="Eina.Future" /> that will resolve when the property is ready to be read.</summary>
60 public Eina.Future GetPropertyReady( System.String property)
61 {
62 return model.GetPropertyReady(property);
63 }
64
65 /// <summary>Gets a number of children from the wrapped model.</summary>
66 public Eina.Future GetChildrenSlice( uint start, uint count)
67 {
68 return model.GetChildrenSlice(start, count);
69 }
70
71 /// <summary>Adds a new object to the wrapper model.</summary>
72 public void Add(T o)
73 {
74 Efl.IModel child = (Efl.IModel)this.AddChild();
75 ModelHelper.SetProperties(o, child);
76 }
77
78 /// <summary>Adds a new childs to the model and returns it.</summary>
79 public Efl.Object AddChild()
80 {
81 return model.AddChild();
82 }
83
84 /// <summary>Deletes the given <c>child</c> from the wrapped model.</summary>
85 public void DelChild( Efl.Object child)
86 {
87 model.DelChild(child);
88 }
89
90 /// <summary>Gets the element at the specified <c>index</c>.</summary>
91 async public System.Threading.Tasks.Task<T> GetAtAsync(uint index)
92 {
93 using (Eina.Value v = await GetChildrenSliceAsync(index, 1))
94 {
95 if (v.GetValueType().IsContainer())
96 {
97 var child = (Efl.IModel)v[0];
98 T obj = (T)Activator.CreateInstance(typeof(T), new System.Object[] {});
99 ModelHelper.GetProperties(obj, child);
100 return obj;
101 }
102 else
103 {
104 throw new System.InvalidOperationException("GetChildrenSlice must have returned a container");
105 }
106 }
107 }
108
109 /// <summary>Async wrapper around <see cref="SetProperty(System.String, Eina.Value)" />.</summary>
110 public System.Threading.Tasks.Task<Eina.Value> SetPropertyAsync( System.String property, Eina.Value value, System.Threading.CancellationToken token=default(System.Threading.CancellationToken))
111 {
112 return model.SetPropertyAsync(property, value, token);
113 }
114
115 /// <summary>Async wrapper around <see cref="GetPropertyReady(System.String)" />.</summary>
116 public System.Threading.Tasks.Task<Eina.Value> GetPropertyReadyAsync( System.String property, System.Threading.CancellationToken token=default(System.Threading.CancellationToken))
117 {
118 return model.GetPropertyReadyAsync(property, token);
119 }
120
121 /// <summary>Async wrapper around <see cref="GetChildrenSlice(uint, uint)" />.</summary>
122 public System.Threading.Tasks.Task<Eina.Value> GetChildrenSliceAsync( uint start, uint count, System.Threading.CancellationToken token=default(System.Threading.CancellationToken))
123 {
124 return model.GetChildrenSliceAsync(start, count, token);
125 }
126
127 /// <summary>Event triggered when properties on the wrapped model changes.</summary>
128 public event EventHandler<Efl.IModelPropertiesChangedEvt_Args> PropertiesChangedEvt
129 {
130 add {
131 model.PropertiesChangedEvt += value;
132 }
133 remove {
134 model.PropertiesChangedEvt -= value;
135 }
136 }
137
138 /// <summary>Event triggered when a child is added from the wrapped model.</summary>
139 public event EventHandler<Efl.IModelChildAddedEvt_Args> ChildAddedEvt
140 {
141 add {
142 model.ChildAddedEvt += value;
143 }
144 remove {
145 model.ChildAddedEvt -= value;
146 }
147 }
148
149 /// <summary>Event triggered when a child is removed from the wrapped model.</summary>
150 public event EventHandler<Efl.IModelChildRemovedEvt_Args> ChildRemovedEvt
151 {
152 add {
153 model.ChildRemovedEvt += value;
154 }
155 remove {
156 model.ChildRemovedEvt -= value;
157 }
158 }
159
160 /// <summary>Event triggered when the number of children changes.</summary>
161 public event EventHandler ChildrenCountChangedEvt
162 {
163 add {
164 model.ChildrenCountChangedEvt += value;
165 }
166 remove {
167 model.ChildrenCountChangedEvt -= value;
168 }
169 }
170}
171
172}
173
174#endif
diff --git a/src/bindings/mono/efl_mono/UserModel.cs b/src/bindings/mono/efl_mono/UserModel.cs
new file mode 100644
index 0000000000..33d2a36be6
--- /dev/null
+++ b/src/bindings/mono/efl_mono/UserModel.cs
@@ -0,0 +1,104 @@
1using System;
2using System.Runtime.InteropServices;
3using System.Collections.Generic;
4using System.Linq;
5using System.ComponentModel;
6using System.Reflection;
7
8namespace Efl {
9
10#if EFL_BETA
11
12internal class ModelHelper
13{
14 /// FIXME Move this to eina_value.cs and be a static method of Value?
15 static internal Eina.Value ValueFromProperty<T>(T source, PropertyInfo property)
16 {
17 return new Eina.Value(property.GetValue(source));
18 }
19
20 static internal void SetPropertyFromValue<T>(T target, PropertyInfo property, Eina.Value v)
21 {
22 property.SetValue(target, v.Unwrap());
23 }
24
25 /// <summary>Sets the properties of the <paramref name="child"/> from the properties of the given object
26 /// <paramref name="o"/>.</summary>
27 static internal void SetProperties<T>(T o, Efl.IModel child)
28 {
29 var properties = typeof(T).GetProperties();
30 foreach(var prop in properties)
31 {
32 child.SetProperty(prop.Name, ValueFromProperty(o, prop));
33 }
34 }
35
36 /// <summary>Sets the properties of <paramref name="o"/> from the properties of <paramref name="child"/>.</summary>
37 static internal void GetProperties<T>(T o, Efl.IModel child)
38 {
39 var properties = typeof(T).GetProperties();
40 foreach(var prop in properties)
41 {
42 using (var v = child.GetProperty(prop.Name))
43 {
44 SetPropertyFromValue(o, prop, v);
45 }
46 }
47 }
48}
49
50/// <summary>Helper class to simplify the creation of MVVM Models based on <see cref="Efl.IModel" />.
51///
52/// <para>This class works together with <see cref="Efl.GenericModel&lt;T&gt;" /> to wrap user defined classes as MVVM models.
53/// Example:</para>
54///
55/// <code>
56/// public class PersonModel
57/// {
58/// public string Name { get; set; }
59/// public int Age { get; set; }
60/// }
61/// // Instantiating the model
62/// var modelData = new Efl.UserModel&lt;PersonModel&gt;(parent);
63/// modelData.Add(new PersonModel { Name = "John", Age = 30 };
64/// var model = new Efl.GenericModel&lt;PersonModel&gt;(modelData, parent);
65/// PersonModel p = await model.GetAtAsync(0);
66/// </code>
67/// </summary>
68[Efl.Eo.BindingEntity]
69public class UserModel<T> : Efl.MonoModelInternal, IDisposable
70{
71 /// <summary>Creates a new model.</summary>
72 /// <param name="parent">The parent of the model.</param>
73 public UserModel (Efl.Object parent = null) : base(Efl.MonoModelInternal.efl_mono_model_internal_class_get(), parent)
74 {
75 var properties = typeof(T).GetProperties();
76 foreach(var prop in properties)
77 {
78 AddProperty(prop.Name, Eina.ValueTypeBridge.GetManaged(prop.PropertyType));
79 }
80 }
81
82 /// <summary>Disposes of this instance.</summary>
83 ~UserModel()
84 {
85 Dispose(false);
86 }
87
88 /// <summary>Adds a new child to the model wrapping the properites of <c>o</c>
89 ///
90 /// <para>Reflection is used to instantiate a new <see cref="Efl.IModel" /> for this child and
91 /// set the mirroring properties correctly.</para>
92 /// </summary>
93 ///
94 /// <param name="o">The user model instance to be added to this model.</param>
95 public void Add (T o)
96 {
97 Efl.IModel child = (Efl.IModel) this.AddChild();
98 ModelHelper.SetProperties(o, child);
99 }
100}
101
102#endif
103
104}
diff --git a/src/bindings/mono/efl_mono/meson.build b/src/bindings/mono/efl_mono/meson.build
index 3edefb3c0c..fb2b2c0431 100644
--- a/src/bindings/mono/efl_mono/meson.build
+++ b/src/bindings/mono/efl_mono/meson.build
@@ -1,6 +1,10 @@
1mono_files += files( 1mono_files += files(
2 'efl_all.cs', 2 'efl_all.cs',
3 'efl_csharp_application.cs' 3 'efl_csharp_application.cs',
4 'UserModel.cs',
5 'GenericModel.cs',
6 'Factory.cs',
7 'Bind.cs'
4 ) 8 )
5 9
6bash = find_program('bash') 10bash = find_program('bash')
@@ -29,3 +33,52 @@ efl_src = configure_file(
29 output: 'efl_libs.cs', 33 output: 'efl_libs.cs',
30 configuration: efl_libs 34 configuration: efl_libs
31) 35)
36
37mono_eo_files = [
38 'efl_mono_model_internal.eo',
39 'efl_mono_model_internal_child.eo'
40]
41
42# mono_eo_c_files = []
43
44pub_eo_file_target = []
45
46foreach eo_file : mono_eo_files
47 pub_eo_file_target += custom_target('eolian_gen_' + eo_file,
48 input : join_paths('..', '..', '..', 'lib', 'efl_mono', eo_file),
49 output : [eo_file + '.h'],
50 depfile : eo_file + '.d',
51 install : false,
52 command : eolian_gen + [ '-I', meson.current_source_dir(), eolian_include_directories,
53 '-o', 'h:' + join_paths(meson.current_build_dir(), eo_file + '.h'),
54 '-o', 'c:' + join_paths(meson.current_build_dir(), eo_file + '.c'),
55 '-o', 'd:' + join_paths(meson.current_build_dir(), eo_file + '.d'),
56 '-gchd', '@INPUT@'])
57 # mono_eo_c_files += join_paths(meson.current_build_dir(), eo_file + '.c')
58endforeach
59
60efl_mono_lib = library('eflcustomexportsmono',
61 [
62 join_paths('..', '..', '..', 'lib', 'efl_mono', 'efl_custom_exports_mono.c'),
63 join_paths('..', '..', '..', 'lib', 'efl_mono', 'efl_mono_model_internal.c'),
64 ],
65 pub_eo_file_target,
66 install : true,
67 include_directories : config_dir + [include_directories(join_paths('.'))],
68 dependencies : [eo, eina, ecore],
69 version : meson.project_version()
70)
71
72foreach eo_file : mono_eo_files
73 if not blacklisted_files.contains(eo_file)
74 mono_generator_target += custom_target('eolian_mono_gen_'+eo_file.underscorify()+'',
75 input : join_paths('..', '..', '..', 'lib', 'efl_mono', eo_file),
76 output : [eo_file + '.cs'],
77 command : [eolian_mono_gen, beta_option, '-I', meson.current_source_dir(), eolian_include_directories,
78 '--dllimport', 'eflcustomexportsmono',
79 '-o', join_paths(meson.current_build_dir(), eo_file + '.cs'),
80 '-e', get_option('mono-examples-dir'),
81 '@INPUT@'])
82
83 endif
84endforeach
diff --git a/src/bindings/mono/eo_mono/FunctionWrapper.cs b/src/bindings/mono/eo_mono/FunctionWrapper.cs
index bdbca77d93..04a5f05614 100644
--- a/src/bindings/mono/eo_mono/FunctionWrapper.cs
+++ b/src/bindings/mono/eo_mono/FunctionWrapper.cs
@@ -131,7 +131,7 @@ public class FunctionLoadResult<T>
131 { 131 {
132 if (_Delegate == null) 132 if (_Delegate == null)
133 { 133 {
134 throw new InvalidOperationException($"Trying to get Delegate while not loaded. Load result: {Kind}"); 134 throw new InvalidOperationException($"Trying to get Delegate of type {typeof(T).FullName} while not loaded. Load result: {Kind}");
135 } 135 }
136 136
137 return _Delegate; 137 return _Delegate;
diff --git a/src/bindings/mono/meson.build b/src/bindings/mono/meson.build
index 5637595f80..8a87da9572 100644
--- a/src/bindings/mono/meson.build
+++ b/src/bindings/mono/meson.build
@@ -82,13 +82,6 @@ blacklisted_files = [
82 'elm_atspi_app_object.eo', 82 'elm_atspi_app_object.eo',
83] 83]
84 84
85efl_mono_lib = library('eflcustomexportsmono',
86 join_paths('..', '..', 'lib', 'efl_mono', 'efl_custom_exports_mono.c'),
87 install : true,
88 dependencies : [eo, eina, ecore],
89 version : meson.project_version()
90)
91
92beta_option = [] 85beta_option = []
93if (get_option('mono-beta')) 86if (get_option('mono-beta'))
94 beta_option = '-b' 87 beta_option = '-b'
diff --git a/src/lib/efl/interfaces/efl_model.eo b/src/lib/efl/interfaces/efl_model.eo
index 40790a5153..b6e78cc04a 100644
--- a/src/lib/efl/interfaces/efl_model.eo
+++ b/src/lib/efl/interfaces/efl_model.eo
@@ -121,7 +121,7 @@ interface @beta Efl.Model
121 ignored.]] 121 ignored.]]
122 } 122 }
123 /* XXX: is this right? */ 123 /* XXX: is this right? */
124 return: future<accessor<Efl.Object>>; [[Array of children]] 124 return: future<array<Efl.Object>>; [[Array of children]]
125 } 125 }
126 @property children_count { 126 @property children_count {
127 get { 127 get {
diff --git a/src/lib/efl_mono/efl_mono_model_internal.c b/src/lib/efl_mono/efl_mono_model_internal.c
new file mode 100644
index 0000000000..cda6d66e14
--- /dev/null
+++ b/src/lib/efl_mono/efl_mono_model_internal.c
@@ -0,0 +1,229 @@
1#ifdef HAVE_CONFIG_H
2# include <config.h>
3#endif
4
5#include "Efl.h"
6#include "Ecore.h"
7#include <Eo.h>
8
9#ifdef EAPI
10# undef EAPI
11#endif
12
13#ifdef _WIN32
14# define EAPI __declspec(dllexport)
15#else
16# ifdef __GNUC__
17# if __GNUC__ >= 4
18# define EAPI __attribute__ ((visibility("default")))
19# else
20# define EAPI
21# endif
22# else
23# define EAPI
24# endif
25#endif /* ! _WIN32 */
26
27
28#include "efl_mono_model_internal.eo.h"
29#include "efl_mono_model_internal_child.eo.h"
30
31#include "assert.h"
32
33typedef struct _Efl_Mono_Model_Internal_Data Efl_Mono_Model_Internal_Data;
34
35typedef struct _Properties_Info Properties_Info;
36struct _Properties_Info
37{
38 const char* name;
39 const Eina_Value_Type* type;
40};
41
42typedef struct _Efl_Mono_Model_Internal_Data
43{
44 Eina_Array *properties_info;
45 Eina_Array *properties_names;
46 Eina_Array *items;
47} _Efl_Mono_Model_Internal_Data;
48
49
50#define MY_CLASS EFL_MONO_MODEL_INTERNAL_CLASS
51
52typedef struct _Efl_Mono_Model_Internal_Child_Data
53{
54 Efl_Mono_Model_Internal_Data* model_pd;
55 size_t index;
56 Eina_Array *values;
57 Eo* child;
58 //Eina_Array *items;
59} Efl_Mono_Model_Internal_Child_Data;
60
61static int _find_property_index (const char* name, Eina_Array* properties_name)
62{
63 int i, size = eina_array_count_get(properties_name);
64 for (i = 0; i != size; ++i)
65 {
66 if (!strcmp(properties_name->data[i], name))
67 {
68 return i;
69 }
70 }
71 return -1;
72}
73
74static Eo *
75_efl_mono_model_internal_efl_object_constructor(Eo *obj, Efl_Mono_Model_Internal_Data *pd)
76{
77 obj = efl_constructor(efl_super(obj, MY_CLASS));
78
79 pd->properties_info = eina_array_new(5);
80 pd->properties_names = eina_array_new(5);
81 pd->items = eina_array_new(5);
82
83 if (!obj) return NULL;
84
85 return obj;
86}
87
88static void
89_efl_mono_model_internal_efl_object_destructor(Eo *obj, Efl_Mono_Model_Internal_Data *pd EINA_UNUSED)
90{
91 efl_destructor(efl_super(obj, MY_CLASS));
92}
93
94static void
95_efl_mono_model_internal_add_property(Eo *obj EINA_UNUSED, Efl_Mono_Model_Internal_Data *pd, const char *name, const Eina_Value_Type *type)
96{
97 Properties_Info* info = malloc(sizeof(Properties_Info));
98 info->name = eina_stringshare_add(name);
99 info->type = type;
100 eina_array_push (pd->properties_info, info);
101 eina_array_push (pd->properties_names, eina_stringshare_add(info->name));
102}
103
104
105static Eina_Iterator *
106_efl_mono_model_internal_efl_model_properties_get(const Eo *obj EINA_UNUSED, Efl_Mono_Model_Internal_Data *pd EINA_UNUSED)
107{
108 return eina_array_iterator_new (NULL);
109}
110
111static Efl_Object*
112_efl_mono_model_internal_efl_model_child_add(Eo *obj, Efl_Mono_Model_Internal_Data *pd)
113{
114 Efl_Mono_Model_Internal_Child* child = efl_add (EFL_MONO_MODEL_INTERNAL_CHILD_CLASS, obj);
115 assert (child != NULL);
116 Efl_Mono_Model_Internal_Child_Data* pcd = efl_data_xref (child, EFL_MONO_MODEL_INTERNAL_CHILD_CLASS, obj);
117 pcd->model_pd = pd;
118 pcd->index = eina_array_count_get(pd->items);
119 pcd->child = child;
120 pcd->values = eina_array_new(5);
121 eina_array_push (pd->items, pcd);
122
123 return child;
124}
125
126static unsigned int
127_efl_mono_model_internal_efl_model_children_count_get(const Eo *obj EINA_UNUSED, Efl_Mono_Model_Internal_Data *pd)
128{
129 return eina_array_count_get(pd->items);
130}
131
132static Eina_Future *
133_efl_mono_model_internal_child_efl_model_property_set(Eo *obj, Efl_Mono_Model_Internal_Child_Data *pd, const char *property, Eina_Value *value)
134{
135 int i = _find_property_index (property, pd->model_pd->properties_names);
136 int j;
137 Eina_Value* old_value;
138 Eina_Value* new_value;
139 Eina_Value tmp_value;
140
141 if (i >= 0)
142 {
143 for (j = i - eina_array_count_get (pd->values); j >= 0; --j)
144 {
145 eina_array_push (pd->values, (void*)1);
146 pd->values->data[pd->values->count-1] = NULL;
147 }
148
149 old_value = eina_array_data_get (pd->values, i);
150 if (old_value)
151 eina_value_free (old_value);
152 new_value = malloc (sizeof(Eina_Value));
153 eina_value_copy (value, new_value);
154 eina_value_copy (value, &tmp_value);
155 eina_array_data_set (pd->values, i, new_value);
156
157
158 return efl_loop_future_resolved(obj, tmp_value);
159 }
160 else
161 {
162 // not found property
163 return efl_loop_future_rejected(obj, EAGAIN);
164 }
165}
166
167static Eina_Value *
168_efl_mono_model_internal_child_efl_model_property_get(const Eo *obj EINA_UNUSED, Efl_Mono_Model_Internal_Child_Data *pd EINA_UNUSED, const char *property EINA_UNUSED)
169{
170 unsigned int i = _find_property_index (property, pd->model_pd->properties_names);
171 if(eina_array_count_get (pd->values) <= i
172 || eina_array_data_get (pd->values, i) == NULL)
173 return eina_value_error_new(EAGAIN);
174 else
175 {
176 Eina_Value* src = eina_array_data_get(pd->values, i);
177 Eina_Value* clone = malloc (sizeof(Eina_Value));
178 eina_value_copy (src, clone);
179 return clone;
180 }
181}
182
183static Eina_Future *
184_efl_mono_model_internal_efl_model_children_slice_get(Eo *obj, Efl_Mono_Model_Internal_Data *pd, unsigned int start, unsigned int count EINA_UNUSED)
185{
186 unsigned int i;
187 Eina_Value array = EINA_VALUE_EMPTY;
188 Efl_Mono_Model_Internal_Child_Data* pcd;
189
190 eina_value_array_setup(&array, EINA_VALUE_TYPE_OBJECT, count % 8);
191
192 for (i = start; i != start + count; ++i)
193 {
194 pcd = eina_array_data_get(pd->items, i);
195 eina_value_array_append (&array, pcd->child);
196 }
197
198 return efl_loop_future_resolved(obj, array);
199}
200
201static Eo *
202_efl_mono_model_internal_child_efl_object_constructor(Eo *obj, Efl_Mono_Model_Internal_Child_Data *pd EINA_UNUSED)
203{
204 obj = efl_constructor(efl_super(obj, EFL_MONO_MODEL_INTERNAL_CHILD_CLASS));
205
206 return obj;
207}
208
209static void
210_efl_mono_model_internal_child_efl_object_destructor(Eo *obj, Efl_Mono_Model_Internal_Child_Data *pd EINA_UNUSED)
211{
212 efl_destructor(efl_super(obj, EFL_MONO_MODEL_INTERNAL_CHILD_CLASS));
213}
214
215static Efl_Object*
216_efl_mono_model_internal_child_efl_model_child_add(Eo *obj EINA_UNUSED, Efl_Mono_Model_Internal_Child_Data *pd EINA_UNUSED)
217{
218 abort();
219 return NULL;
220}
221
222static Eina_Iterator *
223_efl_mono_model_internal_child_efl_model_properties_get(const Eo *obj EINA_UNUSED, Efl_Mono_Model_Internal_Child_Data *pd)
224{
225 return eina_array_iterator_new (pd->model_pd->properties_names);
226}
227
228#include "efl_mono_model_internal.eo.c"
229#include "efl_mono_model_internal_child.eo.c"
diff --git a/src/lib/efl_mono/efl_mono_model_internal.eo b/src/lib/efl_mono/efl_mono_model_internal.eo
new file mode 100644
index 0000000000..3a639defe7
--- /dev/null
+++ b/src/lib/efl_mono/efl_mono_model_internal.eo
@@ -0,0 +1,19 @@
1class @beta Efl.Mono_Model_Internal extends Efl.Loop_Consumer implements Efl.Model
2{
3 methods {
4 add_property {
5 params {
6 @in name: string;
7 @in type: ptr(const(Eina.Value_Type));
8 }
9 }
10 }
11 implements {
12 Efl.Object.constructor;
13 Efl.Object.destructor;
14 Efl.Model.properties { get; }
15 Efl.Model.child_add;
16 Efl.Model.children_count { get; }
17 Efl.Model.children_slice_get;
18 }
19}
diff --git a/src/lib/efl_mono/efl_mono_model_internal_child.eo b/src/lib/efl_mono/efl_mono_model_internal_child.eo
new file mode 100644
index 0000000000..ec8d657ca4
--- /dev/null
+++ b/src/lib/efl_mono/efl_mono_model_internal_child.eo
@@ -0,0 +1,10 @@
1class Efl.Mono_Model_Internal_Child extends Efl.Loop_Consumer implements Efl.Model
2{
3 implements {
4 Efl.Object.constructor;
5 Efl.Object.destructor;
6 Efl.Model.properties { get; }
7 Efl.Model.property { get; set; }
8 Efl.Model.child_add;
9 }
10}
diff --git a/src/tests/efl_mono/Main.cs b/src/tests/efl_mono/Main.cs
index f154f935eb..06add7edd2 100644
--- a/src/tests/efl_mono/Main.cs
+++ b/src/tests/efl_mono/Main.cs
@@ -15,7 +15,7 @@ class TestMain
15 15
16 static int Main(string[] args) 16 static int Main(string[] args)
17 { 17 {
18 Efl.All.Init(); 18 Efl.All.Init(Efl.Csharp.Components.Ui);
19 19
20 bool pass = true; 20 bool pass = true;
21 21
diff --git a/src/tests/efl_mono/Model.cs b/src/tests/efl_mono/Model.cs
new file mode 100644
index 0000000000..a43d9da51c
--- /dev/null
+++ b/src/tests/efl_mono/Model.cs
@@ -0,0 +1,83 @@
1#define CODE_ANALYSIS
2
3using System;
4using System.Threading.Tasks;
5using System.Diagnostics.CodeAnalysis;
6
7#if EFL_BETA
8
9namespace TestSuite {
10
11[SuppressMessage("Gendarme.Rules.Portability", "DoNotHardcodePathsRule")]
12public class TestModel {
13
14 public class VeggieViewModel
15 {
16 public string Name { get; set; }
17 public string Type { get; set; }
18 public string Image { get; set; }
19 }
20
21 private static Efl.UserModel<VeggieViewModel> CreateModel(Efl.Loop loop)
22 {
23 Efl.UserModel<VeggieViewModel> veggies = new Efl.UserModel<VeggieViewModel>(loop);
24 veggies.Add (new VeggieViewModel{ Name="Tomato", Type="Fruit", Image="tomato.png"});
25 veggies.Add (new VeggieViewModel{ Name="Romaine Lettuce", Type="Vegetable", Image="lettuce.png"});
26 veggies.Add (new VeggieViewModel{ Name="Zucchini", Type="Vegetable", Image="zucchini.png"});
27
28 return veggies;
29 }
30
31 public static void reflection_test ()
32 {
33 Efl.Loop loop = Efl.App.AppMain;
34
35 var veggies = CreateModel(loop);
36 }
37
38 internal static async Task EasyModelExtractionAsync (Efl.Loop loop)
39 {
40 var veggies = CreateModel(loop);
41
42 var model = new Efl.GenericModel<VeggieViewModel>(veggies, loop);
43 Test.AssertEquals(3, (int)model.GetChildrenCount());
44
45 VeggieViewModel r2 = await model.GetAtAsync(1);
46 Test.AssertEquals(r2.Name, "Romaine Lettuce");
47
48 VeggieViewModel r = await model.GetAtAsync(0);
49 Test.AssertEquals(r.Name, "Tomato");
50
51 loop.End();
52 }
53
54 public static void easy_model_extraction ()
55 {
56 Efl.Loop loop = Efl.App.AppMain;
57 Task task = EasyModelExtractionAsync(loop);
58
59 loop.Begin();
60
61 task.Wait();
62 }
63
64 public static void factory_test ()
65 {
66 string propertyBound = null;
67 bool callbackCalled = false;
68 var factory = new Efl.Ui.ItemFactory<Efl.Ui.Button>();
69 factory.PropertyBoundEvt += (object sender, Efl.Ui.IPropertyBindPropertyBoundEvt_Args args) => {
70 propertyBound = args.arg;
71 callbackCalled = true;
72 };
73
74 factory.Style().Bind("first name");
75
76 Test.Assert(callbackCalled, "Property bound callback must have been called.");
77 Test.AssertEquals(propertyBound, "style");
78 }
79}
80
81}
82
83#endif
diff --git a/src/tests/efl_mono/meson.build b/src/tests/efl_mono/meson.build
index e464cdd2a8..445c823caa 100644
--- a/src/tests/efl_mono/meson.build
+++ b/src/tests/efl_mono/meson.build
@@ -72,6 +72,7 @@ efl_mono_src = [
72 'Events.cs', 72 'Events.cs',
73 'FunctionPointers.cs', 73 'FunctionPointers.cs',
74 'FunctionPointerMarshalling.cs', 74 'FunctionPointerMarshalling.cs',
75 'Model.cs',
75 'Parts.cs', 76 'Parts.cs',
76 'Promises.cs', 77 'Promises.cs',
77 'Strbuf.cs', 78 'Strbuf.cs',
@@ -111,7 +112,7 @@ custom_target('copy_efl_mono_lib_dll',
111 command : [copy_prog, '@INPUT@', '@OUTPUT@']) 112 command : [copy_prog, '@INPUT@', '@OUTPUT@'])
112endif 113endif
113 114
114config_libs = ['eina', 'ecore', 'eo', 'efl', 'evas', 'eldbus', 'elementary'] 115config_libs = ['eina', 'ecore', 'eo', 'efl', 'evas', 'eldbus', 'elementary', 'efl_mono']
115load_lib = efl_mono_test_suite_path + ':' 116load_lib = efl_mono_test_suite_path + ':'
116 117
117foreach config : config_libs 118foreach config : config_libs