1 #ifdef HAVE_CONFIG_H
2 # include "elementary_config.h"
3 #endif
4 #include <Eo.h>
5 #include <Efl.h>
6 #include <Elementary.h>
7
8 #include "elm_priv.h"
9 #include "elm_genlist_eo.h"
10
11 #include <assert.h>
12
13 #define MY_CLASS ELM_VIEW_LIST_CLASS
14 #define MY_CLASS_NAME "View List"
15
16 typedef struct _Elm_View_List_Data Elm_View_List_Data;
17 typedef struct _View_List_ItemData View_List_ItemData;
18 typedef struct _View_List_ValueItem View_List_ValueItem;
19
20 struct _Elm_View_List_Data
21 {
22 Eo *view;
23 Evas_Object *genlist;
24 View_List_ItemData *rootdata;
25 Elm_Genlist_Item_Class *itc;
26 Elm_Genlist_Item_Type itype;
27
28 struct {
29 Eina_Hash *properties;
30 Eo *model;
31 } connect;
32 };
33
34 struct _View_List_ItemData
35 {
36 Elm_View_List_Data *priv;
37 Elm_Object_Item *item;
38 Eo *model;
39 View_List_ItemData *parent;
40 Eina_List *values;
41 };
42
43 struct _View_List_ValueItem
44 {
45 Eina_Stringshare *part;
46 Eina_Value *value;
47 Elm_Object_Item *item;
48 };
49
50 static void _efl_model_load_children(View_List_ItemData *);
51 static void _efl_model_children_added_cb(void *, const Efl_Event *event);
52 static void _efl_model_children_removed_cb(void *, const Efl_Event *event);
53 static void _efl_model_properties_change_cb(void *, const Efl_Event *event);
54
55 static void _expand_request_cb(void *data EINA_UNUSED, const Efl_Event *event);
56 static void _contract_request_cb(void *data EINA_UNUSED, const Efl_Event *event);
57 static void _contracted_cb(void *data EINA_UNUSED, const Efl_Event *event);
58
59 /* --- Genlist Callbacks --- */
60 EFL_CALLBACKS_ARRAY_DEFINE(model_callbacks,
61 { EFL_MODEL_EVENT_CHILD_ADDED, _efl_model_children_added_cb },
62 { EFL_MODEL_EVENT_CHILD_REMOVED, _efl_model_children_removed_cb });
63 EFL_CALLBACKS_ARRAY_DEFINE(genlist_callbacks,
64 { ELM_GENLIST_EVENT_EXPAND_REQUEST, _expand_request_cb },
65 { ELM_GENLIST_EVENT_CONTRACT_REQUEST, _contract_request_cb },
66 { ELM_GENLIST_EVENT_CONTRACTED, _contracted_cb });
67
68 static void
_item_sel_cb(void * data,Evas_Object * obj EINA_UNUSED,void * event_info EINA_UNUSED)69 _item_sel_cb(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
70 {
71 View_List_ItemData *idata = data;
72
73 EINA_SAFETY_ON_NULL_RETURN(idata);
74
75 efl_event_callback_legacy_call(idata->priv->view, ELM_VIEW_LIST_EVENT_MODEL_SELECTED, idata->model);
76 }
77
78 static void
_item_del(void * data,Evas_Object * obj EINA_UNUSED)79 _item_del(void *data, Evas_Object *obj EINA_UNUSED)
80 {
81 View_List_ItemData *idata = data;
82
83 if (!idata) return;
84
85 efl_event_callback_array_del(idata->model, model_callbacks(), idata);
86 efl_event_callback_del(idata->model, EFL_MODEL_EVENT_PROPERTIES_CHANGED, _efl_model_properties_change_cb, idata);
87
88 efl_unref(idata->model);
89 idata->model = NULL;
90 idata->item = NULL;
91 idata->parent = NULL;
92 idata->priv = NULL;
93
94 free(idata);
95 }
96
97 static Evas_Object *
_item_content_get(void * data,Evas_Object * obj EINA_UNUSED,const char * part)98 _item_content_get(void *data, Evas_Object *obj EINA_UNUSED, const char *part)
99 {
100 const Eina_Value_Type *vtype;
101 const char *prop;
102 Eina_Value *value = NULL;
103 Evas_Object *content = NULL;
104 View_List_ItemData *idata = data;
105 EINA_SAFETY_ON_NULL_RETURN_VAL(data, NULL);
106 EINA_SAFETY_ON_NULL_RETURN_VAL(part, NULL);
107
108 if (!idata->item) return NULL;
109
110 prop = eina_hash_find(idata->priv->connect.properties, part);
111 // If no property are connected, let's not try to guess randomly.
112 if (!prop) return NULL;
113
114 value = efl_model_property_get(idata->model, prop);
115 if (value == NULL) return NULL;
116
117 vtype = eina_value_type_get(value);
118 if (vtype == EINA_VALUE_TYPE_BLOB)
119 {
120 Eina_Value_Blob out;
121
122 eina_value_get(value, &out);
123 if (out.memory != NULL)
124 {
125 content = elm_image_add(obj);
126 //XXX: need copy memory??
127 elm_image_memfile_set(content, out.memory, out.size, NULL, NULL);
128 }
129 }
130 else if (vtype == EINA_VALUE_TYPE_FILE)
131 {
132 Eina_File *f = NULL;
133
134 eina_value_get(value, &f);
135
136 content = elm_image_add(obj);
137 elm_image_mmap_set(content, f, NULL);
138 }
139 else if (vtype == EINA_VALUE_TYPE_OBJECT)
140 {
141 eina_value_get(value, &content);
142 }
143 else
144 {
145 char *str = NULL;
146 str = eina_value_to_string(value);
147 content = elm_icon_add(obj);
148 if (elm_icon_standard_set(content, str))
149 {
150 evas_object_size_hint_aspect_set(content, EVAS_ASPECT_CONTROL_VERTICAL, 1, 1);
151 }
152 else
153 {
154 evas_object_del(content);
155 content = NULL;
156 }
157 free(str);
158 }
159 eina_value_free(value);
160
161 return content;
162 }
163
164 static char *
_item_text_get(void * data,Evas_Object * obj EINA_UNUSED,const char * part)165 _item_text_get(void *data, Evas_Object *obj EINA_UNUSED, const char *part)
166 {
167 Eina_Value *value = NULL;
168 const char *prop;
169 char *text = NULL;
170 View_List_ItemData *idata = data;
171
172 EINA_SAFETY_ON_NULL_RETURN_VAL(data, NULL);
173 EINA_SAFETY_ON_NULL_RETURN_VAL(part, NULL);
174 if (!idata->item) return NULL;
175
176 prop = eina_hash_find(idata->priv->connect.properties, part);
177 if (!prop) prop = part;
178
179 value = efl_model_property_get(idata->model, prop);
180 if (value == NULL) return NULL;
181
182 text = eina_value_to_string(value);
183
184 eina_value_free(value);
185
186 return text;
187 }
188
189 static void
_expand_request_cb(void * data EINA_UNUSED,const Efl_Event * event)190 _expand_request_cb(void *data EINA_UNUSED, const Efl_Event *event)
191 {
192 Elm_Object_Item *item = event->info;
193 View_List_ItemData *idata = elm_object_item_data_get(item);
194
195 EINA_SAFETY_ON_NULL_RETURN(idata);
196
197 efl_event_callback_array_add(idata->model, model_callbacks(), idata);
198
199 _efl_model_load_children(idata);
200 }
201
202 static void
_contract_request_cb(void * data EINA_UNUSED,const Efl_Event * event)203 _contract_request_cb(void *data EINA_UNUSED, const Efl_Event *event)
204 {
205 Elm_Object_Item *item = event->info;
206 View_List_ItemData *idata = elm_object_item_data_get(item);
207
208 efl_event_callback_array_del(idata->model, model_callbacks(), idata);
209 elm_genlist_item_expanded_set(item, EINA_FALSE);
210 }
211
212 static void
_contracted_cb(void * data EINA_UNUSED,const Efl_Event * event)213 _contracted_cb(void *data EINA_UNUSED, const Efl_Event *event)
214 {
215 Elm_Object_Item *glit = event->info;
216 elm_genlist_item_subitems_clear(glit);
217 }
218
219 static void
_genlist_deleted(void * data,Evas * e EINA_UNUSED,Evas_Object * obj,void * event_info EINA_UNUSED)220 _genlist_deleted(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED)
221 {
222 Elm_View_List_Data *priv = data;
223
224 if (priv && priv->genlist && priv->genlist == obj)
225 {
226 efl_event_callback_array_del(priv->genlist, genlist_callbacks(), priv);
227 efl_unref(priv->genlist);
228 priv->genlist = NULL;
229 }
230 }
231
232 /* --- Efl_Model Callbacks --- */
233 static void
_efl_model_properties_change_cb(void * data,const Efl_Event * event)234 _efl_model_properties_change_cb(void *data, const Efl_Event *event)
235 {
236 View_List_ItemData *idata = data;
237 Efl_Model_Property_Event *evt = event->info;
238
239 EINA_SAFETY_ON_NULL_RETURN(idata);
240 EINA_SAFETY_ON_NULL_RETURN(evt);
241
242 if (idata->item)
243 elm_genlist_item_update(idata->item);
244 }
245
246 static Eina_Value
_efl_model_load_children_then(void * data,const Eina_Value v,const Eina_Future * ev EINA_UNUSED)247 _efl_model_load_children_then(void *data, const Eina_Value v,
248 const Eina_Future *ev EINA_UNUSED)
249 {
250 View_List_ItemData *pdata = data;
251 Elm_View_List_Data *priv = pdata->priv;
252 unsigned int i, len;
253 Efl_Model *child = NULL;
254
255 if (eina_value_type_get(&v) == EINA_VALUE_TYPE_ERROR)
256 goto end;
257
258 EINA_VALUE_ARRAY_FOREACH(&v, len, i, child)
259 {
260 View_List_ItemData *idata = calloc(1, sizeof(View_List_ItemData));
261 if (!idata) continue ;
262
263 idata->priv = priv;
264 idata->parent = pdata;
265 idata->model = efl_ref(child);
266
267 efl_event_callback_add(idata->model, EFL_MODEL_EVENT_PROPERTIES_CHANGED,
268 _efl_model_properties_change_cb, idata);
269
270 idata->item = elm_genlist_item_append(priv->genlist, priv->itc, idata, pdata->item,
271 priv->itype, _item_sel_cb, idata);
272 }
273
274 if (i > 0 && pdata->item)
275 elm_genlist_item_expanded_set(pdata->item, EINA_TRUE);
276
277 end:
278 return v;
279 }
280
281 static void
_efl_model_load_children(View_List_ItemData * pdata)282 _efl_model_load_children(View_List_ItemData *pdata)
283 {
284 Eina_Future *f;
285
286 f = efl_model_children_slice_get(pdata->priv->connect.model, 0,
287 efl_model_children_count_get(pdata->priv->connect.model));
288 f = eina_future_then(f, _efl_model_load_children_then, pdata, NULL);
289 efl_future_then(pdata->priv->genlist, f);
290 }
291
292 static void
_efl_model_children_removed_cb(void * data,const Efl_Event * event)293 _efl_model_children_removed_cb(void *data, const Efl_Event *event)
294 {
295 Efl_Model_Children_Event* evt = event->info;
296 View_List_ItemData *idata = data;
297 Elm_Object_Item *item;
298 const Eina_List *subitems, *l;
299 unsigned int i = 0;
300
301 subitems = elm_genlist_item_subitems_get(idata->item);
302
303 EINA_LIST_FOREACH(subitems, l, item)
304 {
305 if (i == evt->index) break ;
306 i++;
307 }
308
309 if (i != evt->index) return ;
310 elm_object_item_del(item);
311 }
312
313 static void
_efl_model_children_added_cb(void * data,const Efl_Event * event)314 _efl_model_children_added_cb(void *data, const Efl_Event *event)
315 {
316 Efl_Model_Children_Event* evt = event->info;
317 View_List_ItemData *idata = data;
318 Eina_Future *f;
319
320 f = efl_model_children_slice_get(idata->priv->connect.model, evt->index, 1);
321 f = eina_future_then(f, _efl_model_load_children_then, idata, NULL);
322 efl_future_then(idata->priv->genlist, f);
323 }
324
325 static void
_priv_model_set(Elm_View_List_Data * priv,Eo * model)326 _priv_model_set(Elm_View_List_Data *priv, Eo *model)
327 {
328 if (priv->connect.model)
329 {
330 efl_event_callback_array_del(priv->connect.model, model_callbacks(), priv->rootdata);
331 elm_obj_genlist_clear(priv->genlist);
332 }
333
334 efl_replace(&priv->connect.model, model);
335
336 if (model == NULL) return;
337
338 priv->rootdata->model = priv->connect.model;
339
340 efl_event_callback_array_add(priv->connect.model, model_callbacks(), priv->rootdata);
341 _efl_model_load_children(priv->rootdata);
342 }
343
344 /**
345 * @brief Elm View List Class impl.
346 */
347 static void
_elm_view_list_genlist_set(Eo * obj,Elm_View_List_Data * priv,Evas_Object * genlist,Elm_Genlist_Item_Type itype,const char * istyle)348 _elm_view_list_genlist_set(Eo *obj, Elm_View_List_Data *priv, Evas_Object *genlist,
349 Elm_Genlist_Item_Type itype, const char *istyle)
350 {
351 priv->view = obj;
352 priv->genlist = genlist;
353 priv->itype = itype;
354 EINA_SAFETY_ON_NULL_RETURN(priv->genlist);
355 efl_ref(priv->genlist);
356
357 priv->rootdata = calloc(1, sizeof(View_List_ItemData));
358 priv->rootdata->priv = priv;
359
360 priv->itc = elm_genlist_item_class_new();
361 if (istyle)
362 priv->itc->item_style = strdup(istyle);
363 priv->itc->func.text_get = _item_text_get;
364 priv->itc->func.content_get = _item_content_get;
365 priv->itc->func.state_get = NULL;
366 priv->itc->func.del = _item_del;
367 priv->connect.properties = eina_hash_string_superfast_new(free);
368
369 efl_event_callback_array_add(priv->genlist, genlist_callbacks(), priv);
370 evas_object_event_callback_add(priv->genlist, EVAS_CALLBACK_DEL, _genlist_deleted, priv);
371 }
372
373
374 static void
_elm_view_list_efl_object_destructor(Eo * obj,Elm_View_List_Data * priv)375 _elm_view_list_efl_object_destructor(Eo *obj, Elm_View_List_Data *priv)
376 {
377 EINA_SAFETY_ON_NULL_RETURN(priv);
378 EINA_SAFETY_ON_NULL_RETURN(obj);
379
380 efl_event_callback_array_del(priv->connect.model, model_callbacks(), priv->rootdata);
381
382 elm_obj_genlist_clear(priv->genlist);
383 free((void *)priv->itc->item_style);
384 elm_genlist_item_class_free(priv->itc);
385
386 eina_hash_free(priv->connect.properties);
387 free(priv->rootdata);
388 priv->rootdata = NULL;
389
390 if (priv->genlist)
391 {
392 evas_object_event_callback_del(priv->genlist, EVAS_CALLBACK_DEL, _genlist_deleted);
393 efl_event_callback_array_del(priv->genlist, genlist_callbacks(), priv);
394 efl_unref(priv->genlist);
395 }
396
397 efl_unref(priv->connect.model);
398
399 efl_destructor(efl_super(obj, MY_CLASS));
400 }
401
402 static void
_elm_view_list_evas_object_get(Eo * obj,Elm_View_List_Data * priv,Evas_Object ** widget)403 _elm_view_list_evas_object_get(Eo *obj, Elm_View_List_Data *priv, Evas_Object **widget)
404 {
405 EINA_SAFETY_ON_NULL_RETURN(priv);
406 EINA_SAFETY_ON_NULL_RETURN(obj);
407 EINA_SAFETY_ON_NULL_RETURN(widget);
408
409 *widget = priv->genlist;
410 }
411
412 static void
_elm_view_list_property_connect(Eo * obj EINA_UNUSED,Elm_View_List_Data * priv,const char * property,const char * part)413 _elm_view_list_property_connect(Eo *obj EINA_UNUSED, Elm_View_List_Data *priv,
414 const char *property, const char *part)
415 {
416 EINA_SAFETY_ON_NULL_RETURN(priv);
417
418 EINA_SAFETY_ON_NULL_RETURN(priv->connect.properties);
419 EINA_SAFETY_ON_NULL_RETURN(property);
420 EINA_SAFETY_ON_NULL_RETURN(part);
421
422 free(eina_hash_set(priv->connect.properties, part, strdup(property)));
423 }
424
425 static void
_elm_view_list_model_set(Eo * obj EINA_UNUSED,Elm_View_List_Data * priv,Efl_Model * model)426 _elm_view_list_model_set(Eo *obj EINA_UNUSED, Elm_View_List_Data *priv, Efl_Model *model)
427 {
428 _priv_model_set(priv, model);
429 }
430
431 static Efl_Model *
_elm_view_list_model_get(const Eo * obj EINA_UNUSED,Elm_View_List_Data * priv)432 _elm_view_list_model_get(const Eo *obj EINA_UNUSED, Elm_View_List_Data *priv)
433 {
434 return priv->connect.model;
435 }
436 #include "elm_view_list_eo.c"
437