summaryrefslogtreecommitdiff
path: root/src/lib/eio/eio_model.c
diff options
context:
space:
mode:
authorCedric Bail <cedric@osg.samsung.com>2017-10-25 18:04:31 -0700
committerCedric BAIL <cedric@osg.samsung.com>2018-04-30 14:21:12 -0700
commit4a54ae0b0ad25dc3a8f55ccf5cd531b1ca0dcaae (patch)
treed62f4237778fb34c067ce6541996fb7d783387ac /src/lib/eio/eio_model.c
parentbba8fbe4495e3911284805c8ae93fbf186145e60 (diff)
eio: migrate to the new efl.model API.
Diffstat (limited to 'src/lib/eio/eio_model.c')
-rw-r--r--src/lib/eio/eio_model.c1290
1 files changed, 738 insertions, 552 deletions
diff --git a/src/lib/eio/eio_model.c b/src/lib/eio/eio_model.c
index 282c159..307d5a7 100644
--- a/src/lib/eio/eio_model.c
+++ b/src/lib/eio/eio_model.c
@@ -20,118 +20,41 @@
20#define MY_CLASS EIO_MODEL_CLASS 20#define MY_CLASS EIO_MODEL_CLASS
21#define MY_CLASS_NAME "Eio_Model" 21#define MY_CLASS_NAME "Eio_Model"
22 22
23static void _eio_prop_set_error_cb(void *, Eio_File *, int); 23static void _eio_model_info_free(Eio_Model_Info *info, Eina_Bool model);
24static void _eio_stat_done_cb(void *, Eio_File *, const Eina_Stat *); 24static void _eio_model_efl_model_monitor_add(Eio_Model_Data *priv);
25static void _eio_error_cb(void *, Eio_File *, int error); 25
26static void _eio_done_children_load_cb(void *, Eio_File *); 26EINA_VALUE_STRUCT_DESC_DEFINE(_eina_file_direct_info_desc,
27static void _eio_error_children_load_cb(void *, Eio_File *, int); 27 NULL,
28static void _eio_main_children_load_cb(void *, Eio_File *, const Eina_File_Direct_Info *); 28 sizeof (Eio_Model_Info),
29static Eina_Bool _eio_filter_children_load_cb(void *, Eio_File *, const Eina_File_Direct_Info *); 29 EINA_VALUE_STRUCT_MEMBER(EINA_VALUE_TYPE_ULONG, Eio_Model_Info, path_length),
30 30 EINA_VALUE_STRUCT_MEMBER(EINA_VALUE_TYPE_ULONG, Eio_Model_Info, name_length),
31static void 31 EINA_VALUE_STRUCT_MEMBER(EINA_VALUE_TYPE_ULONG, Eio_Model_Info, name_start),
32_eio_stat_do(Eio_Model_Data *priv) 32 EINA_VALUE_STRUCT_MEMBER(EINA_VALUE_TYPE_UINT, Eio_Model_Info, type),
33{ 33 EINA_VALUE_STRUCT_MEMBER(EINA_VALUE_TYPE_STRINGSHARE, Eio_Model_Info, path));
34 priv->stat_file = eio_file_direct_stat(priv->path, _eio_stat_done_cb, _eio_error_cb, priv);
35}
36
37/** 34/**
38 * Callbacks 35 * Callbacks
39 * Property 36 * Property
40 */ 37 */
41static void 38static void
42_eio_stat_done_cb(void *data, Eio_File *handler EINA_UNUSED, const Eina_Stat *stat) 39_eio_move_done_cb(void *data, Eio_File *handler)
43{ 40{
44 _Eio_Model_Data *priv = data; 41 Eio_Model_Data *pd = ecore_thread_local_data_find(handler->thread, ".pd");
45 _Eio_Property_Promise* p; 42 Eina_Promise *p = data;
46 Eina_List *l;
47 EINA_LIST_FOREACH(priv->property_promises, l, p)
48 {
49 Eina_Value* v = eina_value_new(EINA_VALUE_TYPE_CHAR);
50 switch(p->property)
51 {
52 case EIO_MODEL_PROP_IS_DIR:
53 eina_value_setup(v, EINA_VALUE_TYPE_CHAR);
54 eina_value_set(v, eio_file_is_dir(stat) ? EINA_TRUE : EINA_FALSE);
55 break;
56 case EIO_MODEL_PROP_IS_LNK:
57 eina_value_setup(v, EINA_VALUE_TYPE_CHAR);
58 eina_value_set(v, eio_file_is_lnk(stat) ? EINA_TRUE : EINA_FALSE);
59 break;
60 case EIO_MODEL_PROP_MTIME:
61 eina_value_setup(v, EINA_VALUE_TYPE_DOUBLE);
62 eina_value_set(v, eio_file_mtime(stat));
63 break;
64 case EIO_MODEL_PROP_SIZE:
65 eina_value_setup(v, EINA_VALUE_TYPE_INT64);
66 eina_value_set(v, eio_file_size(stat));
67 break;
68 default:
69 break;
70 };
71
72 efl_promise_value_set(p->promise, v, (Eina_Free_Cb)&eina_value_free);
73 free(p);
74 }
75 eina_list_free(priv->property_promises);
76 priv->property_promises = NULL;
77 43
78 priv->stat_file = NULL; 44 // FIXME: generate events
79}
80 45
81static void 46 eina_promise_resolve(p, eina_value_string_init(pd->path));
82_eio_progress_cb(void *data EINA_UNUSED, Eio_File *handler EINA_UNUSED, const Eio_Progress *info EINA_UNUSED) 47 pd->request.move = NULL;
83{
84 //TODO: implement
85}
86
87static void
88_eio_move_done_cb(void *data, Eio_File *handler EINA_UNUSED)
89{
90 Efl_Model_Property_Event evt;
91 Eio_Model_Data *priv = data;
92 Eina_Array *properties;
93
94 EINA_SAFETY_ON_FALSE_RETURN(efl_ref_count(priv->obj));
95 properties = eina_array_new(20);
96
97 memset(&evt, 0, sizeof(Efl_Model_Property_Event));
98 eina_array_push(properties, _eio_model_prop_names[EIO_MODEL_PROP_PATH]);
99 eina_array_push(properties, _eio_model_prop_names[EIO_MODEL_PROP_FILENAME]);
100 evt.changed_properties = properties;
101
102 efl_event_callback_call(priv->obj, EFL_MODEL_EVENT_PROPERTIES_CHANGED, &evt);
103 eina_array_free(properties);
104} 48}
105 49
106static void 50static void
107_eio_error_cb(void *data EINA_UNUSED, Eio_File *handler EINA_UNUSED, int error) 51_eio_file_error_cb(void *data, Eio_File *handler, int error)
108{ 52{
109 if (error != 0) 53 Eio_Model_Data *pd = ecore_thread_local_data_find(handler->thread, ".pd");
110 { 54 Eina_Promise *p = data;
111 _Eio_Model_Data *priv = data;
112 _Eio_Property_Promise* p;
113 Eina_List *l;
114 WRN("%d: %s.", error, strerror(error));
115
116 EINA_LIST_FOREACH(priv->property_promises, l, p)
117 {
118 efl_promise_failed_set(p->promise, EFL_MODEL_ERROR_UNKNOWN);
119 }
120 eina_list_free(priv->property_promises);
121 priv->property_promises = NULL;
122 55
123 eio_file_cancel(priv->stat_file); 56 eina_promise_reject(p, error);
124 priv->stat_file = NULL; 57 pd->request.move = NULL;
125 }
126}
127
128static void
129_eio_prop_set_error_cb(void *data EINA_UNUSED, Eio_File *handler EINA_UNUSED, int error)
130{
131 if (error != 0)
132 {
133 WRN("%d: %s.", error, strerror(error));
134 }
135} 58}
136 59
137/** 60/**
@@ -141,50 +64,72 @@ _eio_prop_set_error_cb(void *data EINA_UNUSED, Eio_File *handler EINA_UNUSED, in
141static Eina_Bool 64static Eina_Bool
142_efl_model_evt_added_ecore_cb(void *data, int type, void *event) 65_efl_model_evt_added_ecore_cb(void *data, int type, void *event)
143{ 66{
144 Eio_Monitor_Event *evt = event; 67 Eio_Monitor_Event *ev = event;
145 Eio_Model_Data *priv = data; 68 Eio_Model *obj;
69 Eio_Model_Data *pd = data;
146 Efl_Model_Children_Event cevt; 70 Efl_Model_Children_Event cevt;
147 Eina_Value path; 71 Eio_Model_Info *mi;
72 Eina_List *l;
73 Eina_Stringshare *spath = NULL;
74 char *path = NULL;
148 75
149 if (type != EIO_MONITOR_DIRECTORY_CREATED && type != EIO_MONITOR_FILE_CREATED) 76 if (type != EIO_MONITOR_DIRECTORY_CREATED && type != EIO_MONITOR_FILE_CREATED)
150 return EINA_TRUE; 77 return EINA_TRUE;
151 78
152 char *dir = ecore_file_dir_get(evt->filename); 79 if (ev->monitor != pd->monitor) return EINA_TRUE;
153 if (strcmp(priv->path, dir) != 0) 80
81 obj = pd->self;
82
83 path = ecore_file_dir_get(ev->filename);
84 if (strcmp(pd->path, path) != 0)
85 goto end;
86
87 spath = eina_stringshare_add(ev->filename);
88
89 EINA_LIST_FOREACH(pd->files, l, mi)
154 { 90 {
155 free(dir); 91 if (mi->path == spath)
156 return EINA_TRUE; 92 goto end;
157 } 93 }
158 free(dir);
159 94
160 if (priv->children_list) 95 mi = calloc(1, sizeof (Eio_Model_Info));
96 if (!mi) goto end;
97
98 mi->path_length = eina_stringshare_strlen(spath);
99 mi->path = eina_stringshare_ref(spath);
100 mi->name_start = eina_stringshare_strlen(pd->path) + 1;
101 mi->name_length = mi->path_length - mi->name_start;
102 mi->type = EINA_FILE_UNKNOWN;
103 mi->parent_ref = EINA_TRUE;
104
105 // Honor filter on new added file too
106 if (pd->filter.cb)
161 { 107 {
162 Eina_List* cur = priv->children_list; 108 Eina_File_Direct_Info info = { 0 };
163 Eina_Stringshare *spath = eina_stringshare_add(evt->filename);
164 int i;
165 109
166 for (i = 0; cur; ++i, cur = cur->next) 110 info.path_length = mi->path_length;
111 info.name_start = mi->name_start;
112 info.name_length = mi->name_length;
113 info.type = EINA_FILE_UNKNOWN;
114 strcpy(info.path, mi->path);
115
116 if (!pd->filter.cb(pd->filter.data, obj, &info))
167 { 117 {
168 Eio_Model_Data *cur_priv = efl_data_scope_get(cur->data, MY_CLASS); 118 eina_stringshare_del(mi->path);
169 if(cur_priv->path == spath) 119 free(mi);
170 { 120 goto end;
171 eina_stringshare_del(spath);
172 return EINA_TRUE;
173 }
174 } 121 }
175 eina_stringshare_del(spath);
176 } 122 }
177 123
178 cevt.child = efl_add(EIO_MODEL_CLASS, priv->obj, eio_model_path_set(efl_added, evt->filename)); 124 cevt.index = eina_list_count(pd->files);
179 priv->children_list = eina_list_append(priv->children_list, cevt.child); 125 pd->files = eina_list_append(pd->files, mi);
180 cevt.index = eina_list_count(priv->children_list);
181 126
182 eina_value_setup(&path, EINA_VALUE_TYPE_STRING); 127 // Notify of the new child being added
183 eina_value_set(&path, evt->filename); 128 efl_event_callback_call(obj, EFL_MODEL_EVENT_CHILD_ADDED, &cevt);
184 eio_model_children_filter_set(cevt.child, priv->filter_cb, priv->filter_userdata);
185 eina_value_flush(&path);
186 129
187 efl_event_callback_call(priv->obj, EFL_MODEL_EVENT_CHILD_ADDED, &cevt); 130 end:
131 eina_stringshare_del(spath);
132 free(path);
188 133
189 return EINA_TRUE; 134 return EINA_TRUE;
190} 135}
@@ -192,311 +137,637 @@ _efl_model_evt_added_ecore_cb(void *data, int type, void *event)
192static Eina_Bool 137static Eina_Bool
193_efl_model_evt_deleted_ecore_cb(void *data, int type, void *event) 138_efl_model_evt_deleted_ecore_cb(void *data, int type, void *event)
194{ 139{
195 Eio_Monitor_Event *evt = event; 140 Eio_Model_Info *mi;
196 Eio_Model_Data *priv = data; 141 Eina_List *l;
142 Eio_Monitor_Event *ev = event;
143 Eio_Model *obj;
144 Eio_Model_Data *pd = data;
145 Eina_Stringshare *spath = NULL;
146 Efl_Model_Children_Event cevt = { 0 };
147 unsigned int i = 0;
197 148
198 if (type != EIO_MONITOR_DIRECTORY_DELETED && type != EIO_MONITOR_FILE_DELETED) 149 if (type != EIO_MONITOR_DIRECTORY_DELETED && type != EIO_MONITOR_FILE_DELETED)
199 return EINA_TRUE; 150 return EINA_TRUE;
200 151
201 if (priv->children_list) 152 if (ev->monitor != pd->monitor) return EINA_TRUE;
153
154 obj = pd->self;
155
156 spath = eina_stringshare_add(ev->filename);
157
158 // FIXME: Linear search is pretty slow
159 EINA_LIST_FOREACH(pd->files, l, mi)
202 { 160 {
203 Eina_List* cur = priv->children_list; 161 if (mi->path == spath)
204 Eina_Stringshare *spath = eina_stringshare_add(evt->filename); 162 break ;
205 int i; 163 ++i;
164 }
206 165
207 for (i = 0; cur; ++i, cur = cur->next) 166 if (i >= eina_list_count(pd->files))
208 { 167 goto end;
209 Eio_Model_Data *cur_priv = efl_data_scope_get(cur->data, MY_CLASS);
210 if(cur_priv->path == spath)
211 break;
212 }
213 168
214 if (cur) 169 cevt.index = i;
215 { 170 cevt.child = mi->object;
216 Efl_Model_Children_Event cevt;
217 cevt.index = i;
218 cevt.child = cur->data;
219 171
220 efl_event_callback_call(priv->obj, EFL_MODEL_EVENT_CHILD_REMOVED, &cevt); 172 efl_event_callback_call(obj, EFL_MODEL_EVENT_CHILD_REMOVED, &cevt);
221 173
222 priv->children_list = eina_list_remove_list(priv->children_list, cur); 174 // Remove the entry from the files list
223 efl_unref(cevt.child); 175 pd->files = eina_list_remove_list(pd->files, l);
224 }
225 176
226 eina_stringshare_del(spath); 177 // This should trigger the object child destruction if it exist
227 } 178 // resulting in the potential destruction of the child, after
179 // this point mi and info might be freed.
180 _eio_model_info_free(mi, EINA_FALSE);
228 181
229 return EINA_TRUE; 182 end:
230} 183 eina_stringshare_del(spath);
231 184
232static void 185 return EINA_TRUE;
233_eio_monitors_list_load(Eio_Model_Data *priv)
234{
235 priv->mon.mon_event_child_add[0] = EIO_MONITOR_DIRECTORY_CREATED;
236 priv->mon.mon_event_child_add[1] = EIO_MONITOR_FILE_CREATED;
237 priv->mon.mon_event_child_add[2] = EIO_MONITOR_ERROR;
238 priv->mon.mon_event_child_del[0] = EIO_MONITOR_DIRECTORY_DELETED;
239 priv->mon.mon_event_child_del[1] = EIO_MONITOR_FILE_DELETED;
240 priv->mon.mon_event_child_del[2] = EIO_MONITOR_ERROR;
241} 186}
242 187
243/** 188/**
244 * Callbacks 189 * Callbacks
245 * Child Del 190 * Child Del
246 */ 191 */
247static Eina_Bool 192static void
248_eio_filter_child_del_cb(void *data EINA_UNUSED, Eio_File *handler EINA_UNUSED, const Eina_File_Direct_Info *info EINA_UNUSED) 193_eio_del_cleanup(Eio_Model *obj)
249{ 194{
250 return EINA_TRUE; 195 Eio_Model_Data *pd = efl_data_scope_get(obj, EIO_MODEL_CLASS);
196
197 pd->request.del = NULL;
198 efl_unref(obj);
251} 199}
252 200
253static void 201static void
254_eio_progress_child_del_cb(void *data EINA_UNUSED, Eio_File *handler EINA_UNUSED, const Eio_Progress *info EINA_UNUSED) 202_eio_done_unlink_cb(void *data, Eio_File *handler EINA_UNUSED)
255{} 203{
204 Eio_Model *child = data;
205
206 _eio_del_cleanup(child);
207}
256 208
257static void 209static void
258_eio_done_unlink_cb(void *data, Eio_File *handler EINA_UNUSED) 210_eio_error_unlink_cb(void *data, Eio_File *handler EINA_UNUSED, int error)
259{ 211{
260 Eio_Model_Data *priv = data; 212 Eio_Model *child = data;
261 213
262 EINA_SAFETY_ON_NULL_RETURN(priv); 214 ERR("%d: %s.", error, strerror(error));
263 EINA_SAFETY_ON_NULL_RETURN(priv->obj);
264 215
265 efl_unref(priv->obj); 216 _eio_del_cleanup(child);
266} 217}
267 218
268static void 219static void
269_eio_error_unlink_cb(void *data EINA_UNUSED, Eio_File *handler EINA_UNUSED, int error) 220_eio_model_info_free(Eio_Model_Info *info, Eina_Bool model)
270{ 221{
271 Eio_Model_Data *priv = data; 222 if (!info) return ;
272 223
273 ERR("%d: %s.", error, strerror(error)); 224 if (!model)
225 {
226 if (!info->object)
227 {
228 efl_del(info->object);
229 info->object = NULL;
230 }
231 info->child_ref = EINA_FALSE;
232 }
233 else
234 {
235 info->parent_ref = EINA_FALSE;
236 }
274 237
275 efl_unref(priv->obj); 238 if (info->child_ref ||
239 info->parent_ref)
240 return ;
241
242 eina_stringshare_del(info->path);
243 free(info);
276} 244}
277 245
246static Eina_File_Type
247_eio_model_info_type_get(const Eina_File_Direct_Info *info, const Eina_Stat *st)
248{
249 if (info && info->type != EINA_FILE_UNKNOWN)
250 return info->type;
251 if (st)
252 {
253 if (S_ISREG(st->mode))
254 return EINA_FILE_REG;
255 else if (S_ISDIR(st->mode))
256 return EINA_FILE_DIR;
257 else if (S_ISCHR(st->mode))
258 return EINA_FILE_CHR;
259 else if (S_ISBLK(st->mode))
260 return EINA_FILE_BLK;
261 else if (S_ISFIFO(st->mode))
262 return EINA_FILE_FIFO;
263 else if (S_ISLNK(st->mode))
264 return EINA_FILE_LNK;
265 else if (S_ISSOCK(st->mode))
266 return EINA_FILE_SOCK;
267 }
268 return EINA_FILE_UNKNOWN;
269}
278 270
279/** 271static void
280 * Interfaces impl. 272_eio_model_info_build(const Eio_Model *model, Eio_Model_Data *pd)
281 */
282static Eina_Array const *
283_eio_model_efl_model_properties_get(const Eo *obj EINA_UNUSED, Eio_Model_Data *_pd)
284{ 273{
285 Eio_Model_Data *priv = _pd; 274 char *path;
275
276 if (pd->info) goto end;
277
278 pd->info = calloc(1, sizeof (Eio_Model_Info));
279 if (!pd->info) return ;
280
281 pd->info->path_length = eina_stringshare_strlen(pd->path);
282 pd->info->path = eina_stringshare_ref(pd->path);
286 283
287 EINA_SAFETY_ON_NULL_RETURN_VAL(priv, NULL); 284 path = strdup(pd->path);
288 EINA_SAFETY_ON_NULL_RETURN_VAL(priv->obj, NULL); 285 pd->info->name_start = basename(path) - path;
286 pd->info->name_length = pd->info->path_length - pd->info->name_start;
287 free(path);
289 288
290 return priv->properties_name; 289 pd->info->type = _eio_model_info_type_get(NULL, pd->st);
290
291 efl_model_properties_changed(model, "direct_info");
292
293 end:
294 pd->info->parent_ref = EINA_TRUE;
291} 295}
292 296
293/**
294 * Property Get
295 */
296static void 297static void
297_on_idle_mime(void *data, const Efl_Event *ev) 298_eio_child_delete(Eio_Model *child, Eio_Model_Data *child_pd)
298{ 299{
299 Eio_Model_Data *priv = data; 300 Eio_Model *parent;
300 Efl_Promise *p;
301 const char *value;
302 301
303 // Make sure that we are not over consuming time in the main loop 302 if (!child_pd->delete_me) return ;
304 if (ecore_time_get() - ecore_loop_time_get() > 0.004) return ; 303
304 parent = efl_parent_get(child);
305 efl_model_child_del(parent, child);
306}
307
308static void
309_eio_build_st_done(void *data, Eio_File *handler EINA_UNUSED, const Eina_Stat *stat)
310{
311 Eio_Model *model = data;
312 Eio_Model_Data *pd = efl_data_scope_get(model, EIO_MODEL_CLASS);
313
314 if (!pd) return ;
315 pd->request.stat = NULL;
305 316
306 // Are we done yet ? 317 pd->st = malloc(sizeof (Eina_Stat));
307 efl_event_callback_del(ev->object, EFL_LOOP_EVENT_IDLE_ENTER, _on_idle_mime, priv); 318 if (!pd->st) return ;
308 if (!priv->fetching_mime) return ;
309 319
310 value = efreet_mime_type_get(priv->path); 320 memcpy(pd->st, stat, sizeof (Eina_Stat));
311 321
312 EINA_LIST_FREE(priv->fetching_mime, p) 322 if (!pd->info) _eio_model_info_build(model, pd);
323 if (pd->info->type == EINA_FILE_UNKNOWN)
324 pd->info->type = _eio_model_info_type_get(NULL, stat);
325
326 efl_model_properties_changed(model, "mtime", "atime", "ctime", "is_dir", "is_lnk", "size", "stat");
327
328 if (eio_file_is_dir(pd->st))
313 { 329 {
314 Eina_Value *v; 330 // Now that we know we are a directory, we should whatch it
331 _eio_model_efl_model_monitor_add(pd);
315 332
316 v = eina_value_new(EINA_VALUE_TYPE_STRING); 333 // And start listing its child
317 eina_value_set(v, value); 334 efl_model_children_count_get(model);
318 efl_promise_value_set(p, v, (Eina_Free_Cb)&eina_value_free);
319 } 335 }
336
337 _eio_child_delete(model, pd);
320} 338}
321 339
322static Efl_Future* 340static void
323_eio_model_efl_model_property_get(Eo *obj, Eio_Model_Data *priv, const char *property) 341_eio_build_st_error(void *data, Eio_File *handler EINA_UNUSED, int error)
324{ 342{
325 _Eio_Property_Name property_name; 343 Eio_Model *model = data;
326 const char* value = NULL; 344 Eio_Model_Data *pd = efl_data_scope_get(model, EIO_MODEL_CLASS);
327 Efl_Promise *promise;
328 Efl_Future *future;
329 345
330 promise = efl_add(EFL_PROMISE_CLASS, obj); 346 pd->request.stat = NULL;
331 future = efl_promise_future_get(promise); 347 pd->error = error;
332 348
333 EINA_SAFETY_ON_NULL_RETURN_VAL(priv, future); 349 efl_model_properties_changed(model, "direct_info", "mtime", "atime", "ctime", "is_dir", "is_lnk", "size", "stat");
334 350
335 if (property == NULL) 351 _eio_child_delete(model, pd);
336 { 352}
337 efl_promise_failed_set(promise, EFL_MODEL_ERROR_NOT_FOUND);
338 return future;
339 }
340 353
341 if(strcmp(_eio_model_prop_names[EIO_MODEL_PROP_FILENAME], property) == 0) 354static void
342 { 355_eio_build_st(const Eio_Model *model, Eio_Model_Data *pd)
343 char* tmp = strdup(priv->path); 356{
344 char* basename_ = basename(tmp); 357 if (pd->st) return ;
345 value = strdup(basename_); 358 if (pd->request.stat) return ;
346 property_name = EIO_MODEL_PROP_FILENAME; 359 if (pd->error) return ;
347 free(tmp); 360
348 } 361 pd->request.stat = eio_file_direct_stat(pd->path, _eio_build_st_done, _eio_build_st_error, model);
349 else if(strcmp(_eio_model_prop_names[EIO_MODEL_PROP_PATH], property) == 0) 362}
363
364static Eina_List *delayed_queue = NULL;
365
366static void
367_delayed_flush(void *data EINA_UNUSED, const Efl_Event *ev)
368{
369 Eina_Promise *p;
370
371 EINA_LIST_FREE(delayed_queue, p)
372 eina_promise_resolve(p, EINA_VALUE_EMPTY);
373
374 efl_event_callback_del(ev->object, EFL_LOOP_EVENT_IDLE, _delayed_flush, NULL);
375}
376
377static void
378_cancel_request(void *data, const Eina_Promise *dead_ptr EINA_UNUSED)
379{
380 delayed_queue = eina_list_remove_list(delayed_queue, data);
381}
382
383static Eina_Future *
384_build_delay(Efl_Loop *loop)
385{
386 Eina_Promise *p;
387
388 p = eina_promise_new(efl_loop_future_scheduler_get(loop),
389 _cancel_request, NULL);
390
391 if (!delayed_queue)
350 { 392 {
351 value = priv->path; 393 // Remove callback, just in case it is still there.
352 property_name = EIO_MODEL_PROP_PATH; 394 efl_event_callback_del(loop, EFL_LOOP_EVENT_IDLE, _delayed_flush, NULL);
395 efl_event_callback_add(loop, EFL_LOOP_EVENT_IDLE, _delayed_flush, NULL);
396 // FIXME: It would be nice to be able to build a future directly to be triggered on one event
353 } 397 }
354 else if(strcmp(_eio_model_prop_names[EIO_MODEL_PROP_MIME_TYPE], property) == 0) 398
399 delayed_queue = eina_list_append(delayed_queue, p);
400 eina_promise_data_set(p, eina_list_last(delayed_queue));
401
402 return eina_future_new(p);
403}
404
405static Eina_Value
406_eio_build_mime_now(void *data, const Eina_Value v, const Eina_Future *dead_future EINA_UNUSED)
407{
408 Eio_Model *model = data;
409 Eio_Model_Data *pd = efl_data_scope_get(model, EIO_MODEL_CLASS);
410
411 if (v.type == EINA_VALUE_TYPE_ERROR) return v;
412
413 if (!pd->loop) return v;
414
415 // Make sure that we are not over consuming time in the main loop
416 if (delayed_queue || ecore_time_get() - ecore_loop_time_get() > 0.004)
355 { 417 {
356 property_name = EIO_MODEL_PROP_MIME_TYPE; 418 return eina_future_as_value(eina_future_then(_build_delay(pd->loop),
419 _eio_build_mime_now, model));
357 } 420 }
358 else if(strcmp(_eio_model_prop_names[EIO_MODEL_PROP_MTIME], property) == 0) 421
359 property_name = EIO_MODEL_PROP_MTIME; 422 pd->mime_type = efreet_mime_type_get(pd->path);
360 else if(strcmp(_eio_model_prop_names[EIO_MODEL_PROP_IS_DIR], property) == 0) 423
361 property_name = EIO_MODEL_PROP_IS_DIR; 424 efl_wref_del(pd->loop, &pd->loop);
362 else if(strcmp(_eio_model_prop_names[EIO_MODEL_PROP_IS_LNK], property) == 0) 425 pd->loop = NULL;
363 property_name = EIO_MODEL_PROP_IS_LNK; 426 pd->request.mime = NULL;
364 else if(strcmp(_eio_model_prop_names[EIO_MODEL_PROP_SIZE], property) == 0) 427
365 property_name = EIO_MODEL_PROP_SIZE; 428 efl_model_properties_changed(model, "mime_type");
366 else 429
430 return v;
431}
432
433static void
434_eio_build_mime(const Efl_Object *model, Eio_Model_Data *pd)
435{
436 Eina_Future *f;
437
438 if (pd->mime_type) return ;
439 if (pd->request.mime) return ;
440
441 efl_wref_add(efl_provider_find(model, EFL_LOOP_CLASS), &pd->loop);
442
443 f = efl_loop_job(pd->loop);
444 f = eina_future_then(f, _eio_build_mime_now, model);
445 pd->request.mime = efl_future_Eina_FutureXXX_then(model, f);
446}
447
448static Eina_Value *
449_property_filename_cb(const Eo *obj, Eio_Model_Data *pd)
450{
451 _eio_model_info_build(obj, pd);
452 if (pd->info)
453 return eina_value_string_new(pd->info->path + pd->info->name_start);
454 return eina_value_error_new(EAGAIN);
455}
456
457static Eina_Value *
458_property_path_cb(const Eo *obj EINA_UNUSED, Eio_Model_Data *pd)
459{
460 return eina_value_string_new(pd->path);
461}
462
463static Eina_Value *
464_property_direct_info_cb(const Eo *obj, Eio_Model_Data *pd)
465{
466 _eio_model_info_build(obj, pd);
467
468 if (pd->info)
367 { 469 {
368 efl_promise_failed_set(promise, EFL_MODEL_ERROR_NOT_FOUND); 470 Eina_Value *r;
369 return future; 471
472 r = eina_value_struct_new(_eina_file_direct_info_desc());
473 if (!r) return NULL;
474 if (!eina_value_pset(r, pd->info))
475 {
476 eina_value_free(r);
477 return NULL;
478 }
479
480 return r;
370 } 481 }
482 if (pd->error)
483 return eina_value_error_new(pd->error);
484 return eina_value_error_new(EAGAIN);
485}
486
487#define TIMECB(Prop) \
488 static Eina_Value * \
489 _property_##Prop##_cb(const Eo *obj, Eio_Model_Data *pd) \
490 { \
491 if (pd->st) \
492 return eina_value_time_new(pd->st->Prop); \
493 if (pd->error) \
494 return eina_value_error_new(pd->error); \
495 \
496 _eio_build_st(obj, pd); \
497 return eina_value_error_new(EAGAIN); \
498 }
499
500TIMECB(mtime);
501TIMECB(atime);
502TIMECB(ctime);
503
504static Eina_Value *
505_property_is_dir_cb(const Eo *obj, Eio_Model_Data *pd)
506{
507 if (pd->st)
508 return eina_value_bool_new(eio_file_is_dir(pd->st));
509 if (pd->error)
510 return eina_value_error_new(pd->error);
511
512 _eio_build_st(obj, pd);
513 return eina_value_error_new(EAGAIN);
514}
371 515
372 switch(property_name) 516static Eina_Value *
517_property_is_lnk_cb(const Eo *obj, Eio_Model_Data *pd)
518{
519 if (pd->st)
520 return eina_value_bool_new(eio_file_is_lnk(pd->st));
521 if (pd->error)
522 return eina_value_error_new(pd->error);
523
524 _eio_build_st(obj, pd);
525 return eina_value_error_new(EAGAIN);
526}
527
528static Eina_Value *
529_property_size_cb(const Eo *obj, Eio_Model_Data *pd)
530{
531 if (pd->st)
532 return eina_value_ulong_new(pd->st->size);
533 if (pd->error)
534 return eina_value_error_new(pd->error);
535
536 _eio_build_st(obj, pd);
537 return eina_value_ulong_new(EAGAIN);
538}
539
540static Eina_Value *
541_property_stat_cb(const Eo *obj, Eio_Model_Data *pd)
542{
543 if (pd->st)
373 { 544 {
374 case EIO_MODEL_PROP_MIME_TYPE: 545 Eina_Value *r;
375 { 546
376 if (!priv->fetching_mime) 547 r = eina_value_struct_new(_eina_stat_desc());
377 efl_event_callback_add(efl_provider_find(obj, EFL_LOOP_CLASS), 548 if (!r) return NULL;
378 EFL_LOOP_EVENT_IDLE_ENTER, _on_idle_mime, priv); 549 if (!eina_value_pset(r, pd->info))
379 priv->fetching_mime = eina_list_append(priv->fetching_mime, promise); 550 {
380 break; 551 eina_value_free(r);
381 } 552 return NULL;
382 case EIO_MODEL_PROP_FILENAME: 553 }
383 case EIO_MODEL_PROP_PATH: 554
384 { 555 return r;
385 Eina_Value* v = eina_value_new(EINA_VALUE_TYPE_STRING);
386 eina_value_set(v, value);
387 efl_promise_value_set(promise, v, (Eina_Free_Cb)&eina_value_free);
388
389 break;
390 }
391 default:
392 {
393 _Eio_Property_Promise* p = calloc(1, sizeof(_Eio_Property_Promise));
394 p->promise = promise;
395 p->property = property_name;;
396 priv->property_promises = eina_list_prepend(priv->property_promises, p);
397
398 if (!priv->stat_file)
399 _eio_stat_do(priv);
400 break;
401 }
402 } 556 }
403 return future; 557 if (pd->error)
558 return eina_value_error_new(pd->error);
559
560 _eio_build_st(obj, pd);
561 return eina_value_error_new(EAGAIN);
562}
563
564static Eina_Value *
565_property_mime_type_cb(const Eo *obj, Eio_Model_Data *pd)
566{
567 if (pd->mime_type)
568 return eina_value_string_new(pd->mime_type);
569
570 _eio_build_mime(obj, pd);
571 return eina_value_error_new(EAGAIN);
404} 572}
405 573
574#define PP(Name) \
575 { #Name, _property_##Name##_cb }
576
577static struct {
578 const char *name;
579 Eina_Value *(*cb)(const Eo *obj, Eio_Model_Data *pd);
580} properties[] = {
581 PP(filename), PP(path),
582 PP(direct_info),
583 PP(mtime), PP(atime), PP(ctime), PP(is_dir), PP(is_lnk), PP(size),
584 PP(stat),
585 PP(mime_type)
586};
587
406/** 588/**
407 * Property Set 589 * Interfaces impl.
408 */ 590 */
409static Efl_Future* 591static Eina_Array *
410_eio_model_efl_model_property_set(Eo *obj EINA_UNUSED, 592_eio_model_efl_model_properties_get(const Eo *obj EINA_UNUSED,
411 Eio_Model_Data *priv, 593 Eio_Model_Data *pd EINA_UNUSED)
412 const char * property, 594{
413 const Eina_Value *value) 595 Eina_Array *r;
596 unsigned int i;
597
598 r = eina_array_new(4);
599 for (i = 0; i < EINA_C_ARRAY_LENGTH(properties); ++i)
600 eina_array_push(r, properties[i].name);
601
602 return r;
603}
604
605static Eina_Value *
606_eio_model_efl_model_property_get(const Eo *obj, Eio_Model_Data *pd, const char *property)
607{
608 unsigned int i;
609
610 if (!property) return NULL;
611 if (pd->error) return eina_value_error_new(pd->error);
612
613 for (i = 0; i < EINA_C_ARRAY_LENGTH(properties); ++i)
614 if (property == properties[i].name ||
615 !strcmp(property, properties[i].name))
616 return properties[i].cb(obj, pd);
617
618 ERR("Could not find property '%s'.", property);
619 // Unknow value request
620 return efl_model_property_get(efl_super(obj, EIO_MODEL_CLASS), property);
621}
622
623static Eina_Future *
624_eio_model_efl_model_property_set(Eo *obj,
625 Eio_Model_Data *pd,
626 const char *property, Eina_Value *value)
414{ 627{
415 Eo *loop = efl_provider_find(obj, EFL_LOOP_CLASS); 628 Eo *loop = efl_provider_find(obj, EFL_LOOP_CLASS);
416 Efl_Promise *promise = efl_add(EFL_PROMISE_CLASS, loop); 629 const char *path;
417 Efl_Future* future = efl_promise_future_get(promise); 630 Eina_Future *f;
418 char *dest; 631 Eina_Value s = EINA_VALUE_EMPTY;
632 Eina_Error err = EFL_MODEL_ERROR_NOT_FOUND;
633 Eina_Bool finalized = !!pd->path;
634
635 if (!property) goto on_error;
419 636
420 EINA_SAFETY_ON_NULL_RETURN_VAL(property, future); 637 err = EFL_MODEL_ERROR_NOT_SUPPORTED;
638 if (strcmp(property, "path") != 0) goto on_error;
421 639
422 if (strcmp(property, "path") != 0) 640 if (finalized && pd->request.move) goto on_error;
641
642 err = EFL_MODEL_ERROR_UNKNOWN;
643 if (!eina_value_setup(&s, EINA_VALUE_TYPE_STRING)) goto on_error;
644 if (!eina_value_convert(value, &s)) goto on_error;
645 if (!eina_value_string_get(&s, &path)) goto on_error;
646
647 eina_stringshare_replace(&pd->path, path);
648
649 if (finalized)
423 { 650 {
424 efl_promise_failed_set(promise, EFL_MODEL_ERROR_NOT_SUPPORTED); 651 Eina_Promise *p = eina_promise_new(efl_loop_future_scheduler_get(loop),
425 return future; 652 _efl_io_manager_future_cancel, NULL);
426 } 653 f = eina_future_new(p);
654
655 pd->request.move = eio_file_move(pd->path, path,
656 NULL, /* FIXME: have a move progress property */
657 _eio_move_done_cb, _eio_file_error_cb, p);
427 658
428 if (!eina_value_get(value, &dest)) 659 ecore_thread_local_data_add(pd->request.move->thread, ".pd", pd, NULL, EINA_TRUE);
660 eina_promise_data_set(p, pd->request.move);
661
662 // FIXME: turn on monitor in the finalize stage or after move
663 }
664 else
429 { 665 {
430 efl_promise_failed_set(promise, EFL_MODEL_ERROR_UNKNOWN); 666 f = eina_future_resolved(efl_loop_future_scheduler_get(loop),
431 return future; 667 eina_value_string_init(pd->path));
432 } 668 }
433 669
434 if (priv->path == NULL || !ecore_file_exists(priv->path)) 670 return efl_future_Eina_FutureXXX_then(obj, f);
671
672 on_error:
673 return eina_future_rejected(efl_loop_future_scheduler_get(loop), err);
674}
675
676static void
677_eio_model_children_list(void *data, Eina_Array *entries)
678{
679 Eina_File_Direct_Info *info;
680 Efl_Model *obj = data;
681 Eio_Model_Data *pd;
682 Efl_Model_Children_Event cevt = { 0 };
683 Eina_Array_Iterator iterator;
684 unsigned int i;
685
686 pd = efl_data_scope_get(obj, EIO_MODEL_CLASS);
687 if (!pd) return ;
688
689 EINA_ARRAY_ITER_NEXT(entries, i, info, iterator)
435 { 690 {
436 eina_stringshare_replace(&priv->path, dest); 691 Eio_Model_Info *mi;
437 692
438 if (!ecore_file_exists(priv->path)) 693 if (pd->filter.cb)
439 { 694 {
440 efl_promise_failed_set(promise, EFL_MODEL_ERROR_NOT_FOUND); 695 if (!pd->filter.cb(pd->filter.data, obj, info))
441 return future; 696 continue ;
442 } 697 }
443 698
444 char* tmp = strdup(priv->path); 699 mi = calloc(1, sizeof (Eio_Model_Info));
445 char* basename_ = basename(tmp); 700 if (!mi) continue ;
446 INF("path '%s' with filename '%s'.", priv->path, basename_);
447 free(tmp);
448 (void)basename_;
449 701
450 _eio_monitors_list_load(priv); 702 mi->path_length = info->path_length;
703 mi->path = eina_stringshare_add(info->path);
451 704
452 _eio_move_done_cb(priv, NULL); 705 mi->name_start = info->name_start;
453 } 706 mi->name_length = info->name_length;
454 else 707 mi->type = _eio_model_info_type_get(info, NULL);
455 { 708 mi->parent_ref = EINA_TRUE;
456 priv->move_file = eio_file_move(priv->path, dest, _eio_progress_cb, _eio_move_done_cb, _eio_prop_set_error_cb, priv); 709
457 eina_stringshare_replace(&priv->path, dest); 710 cevt.index = eina_list_count(pd->files);
711 cevt.child = NULL;
712
713 pd->files = eina_list_append(pd->files, mi);
714
715 efl_event_callback_call(obj, EFL_MODEL_EVENT_CHILD_ADDED, &cevt);
458 } 716 }
717}
718
719static Eina_Value
720_eio_model_children_list_on(void *data, const Eina_Value v,
721 const Eina_Future *dead EINA_UNUSED)
722{
723 Eio_Model_Data *pd = data;
724
725 pd->request.listing = NULL;
726 pd->listed = EINA_TRUE;
459 727
460 efl_promise_value_set(promise, &value, NULL); 728 // Now that we have listed the content of the directory,
461 return future; 729 // we can whatch over it
730 _eio_model_efl_model_monitor_add(pd);
731
732 return v;
462} 733}
463 734
464/** 735/**
465 * Children Count Get 736 * Children Count Get
466 */ 737 */
467static Efl_Future* 738static unsigned int
468_eio_model_efl_model_children_count_get(Eo *obj EINA_UNUSED, Eio_Model_Data *priv) 739_eio_model_efl_model_children_count_get(const Eo *obj, Eio_Model_Data *pd)
469{ 740{
470 Eo *loop = efl_provider_find(obj, EFL_LOOP_CLASS); 741 // If we have no information on the object, let's build it.
471 Efl_Promise *promise = efl_add(EFL_PROMISE_CLASS, loop); 742 if (efl_invalidated_get(obj))
472 Efl_Future* future = efl_promise_future_get(promise);
473
474 if (!priv->path)
475 { 743 {
476 efl_promise_failed_set(promise, EFL_MODEL_ERROR_INIT_FAILED); 744 return 0;
477 return future;
478 } 745 }
479 746 else if (!pd->info)
480 if (!(priv->is_listed)) 747 {
748 _eio_build_st(obj, pd);
749 }
750 else if (!pd->listed &&
751 !pd->request.listing &&
752 pd->info->type == EINA_FILE_DIR)
481 { 753 {
482 priv->count_promises = eina_list_prepend(priv->count_promises, promise); 754 Efl_Io_Manager *iom;
755 Eina_Future *f;
483 756
484 if (priv->is_listing == EINA_FALSE) 757 iom = efl_provider_find(obj, EFL_IO_MANAGER_CLASS);
758 if (!iom)
485 { 759 {
486 priv->is_listing = EINA_TRUE; 760 ERR("Could not find an Efl.Io.Manager on %p.", obj);
487 eio_file_direct_ls(priv->path, _eio_filter_children_load_cb, 761 return 0;
488 _eio_main_children_load_cb, _eio_done_children_load_cb,
489 _eio_error_children_load_cb, priv);
490 } 762 }
491 } 763
492 else 764 f = efl_io_manager_direct_ls(iom, pd->path, EINA_FALSE,
493 { 765 (void*) obj, _eio_model_children_list, NULL);
494 unsigned int *c = calloc(1, sizeof(unsigned int)); 766 f = eina_future_then(f, _eio_model_children_list_on, pd);
495 *c = eina_list_count(priv->children_list); 767 pd->request.listing = efl_future_Eina_FutureXXX_then(obj, f);
496 efl_promise_value_set(promise, c, free);
497 } 768 }
498 769
499 return future; 770 return eina_list_count(pd->files);
500} 771}
501 772
502static void 773static void
@@ -504,9 +775,10 @@ _eio_model_efl_model_monitor_add(Eio_Model_Data *priv)
504{ 775{
505 if (!priv->monitor) 776 if (!priv->monitor)
506 { 777 {
507 priv->monitor = eio_monitor_add(priv->path);
508 int i = 0; 778 int i = 0;
509 779
780 priv->monitor = eio_monitor_add(priv->path);
781
510 for (i = 0; priv->mon.mon_event_child_add[i] != EIO_MONITOR_ERROR ; ++i) 782 for (i = 0; priv->mon.mon_event_child_add[i] != EIO_MONITOR_ERROR ; ++i)
511 priv->mon.ecore_child_add_handler[i] = 783 priv->mon.ecore_child_add_handler[i] =
512 ecore_event_handler_add(priv->mon.mon_event_child_add[i], _efl_model_evt_added_ecore_cb, priv); 784 ecore_event_handler_add(priv->mon.mon_event_child_add[i], _efl_model_evt_added_ecore_cb, priv);
@@ -538,224 +810,142 @@ _eio_model_efl_model_monitor_del(Eio_Model_Data *priv)
538 * Callbacks 810 * Callbacks
539 * Children Load 811 * Children Load
540 */ 812 */
541static Eina_Bool 813static void
542_eio_filter_children_load_cb(void *data, Eio_File *handler, const Eina_File_Direct_Info *info) 814_eio_model_children_filter_set(Eo *obj EINA_UNUSED, Eio_Model_Data *pd,
815 void *filter_data, EflIoFilter filter, Eina_Free_Cb filter_free_cb)
543{ 816{
544 Eio_Model_Data *priv = data; 817 pd->filter.data = filter_data;
545 EINA_SAFETY_ON_NULL_RETURN_VAL(priv, EINA_FALSE); 818 pd->filter.cb = filter;
546 819 pd->filter.free = filter_free_cb;
547 eina_spinlock_take(&priv->filter_lock);
548 if (priv->filter_cb)
549 {
550 Eina_Bool r = priv->filter_cb(priv->filter_userdata, handler, info);
551 eina_spinlock_release(&priv->filter_lock);
552 return r;
553 }
554 else
555 eina_spinlock_release(&priv->filter_lock);
556
557 return EINA_TRUE;
558} 820}
559 821
560static void 822/**
561_eio_main_children_load_cb(void *data, Eio_File *handler EINA_UNUSED, const Eina_File_Direct_Info *info) 823 * Child Add
824 */
825static Eo *
826_eio_model_efl_model_child_add(Eo *obj EINA_UNUSED, Eio_Model_Data *priv EINA_UNUSED)
562{ 827{
563 Eo *child; 828 return NULL;
564 Eio_Model_Data *priv = data;
565 EINA_SAFETY_ON_NULL_RETURN(priv);
566
567 child = efl_add_ref(MY_CLASS, priv->obj, eio_model_path_set(efl_added, info->path));
568 eina_spinlock_take(&priv->filter_lock);
569 if (priv->filter_cb)
570 eio_model_children_filter_set(child, priv->filter_cb, priv->filter_userdata);
571 eina_spinlock_release(&priv->filter_lock);
572
573 priv->children_list = eina_list_append(priv->children_list, child);
574} 829}
575 830
831/**
832 * Child Remove
833 */
576static void 834static void
577_eio_done_children_load_cb(void *data, Eio_File *handler EINA_UNUSED) 835_eio_model_efl_model_child_del(Eo *obj EINA_UNUSED,
836 Eio_Model_Data *priv EINA_UNUSED,
837 Eo *child)
578{ 838{
579 Eio_Model_Data *priv = data; 839 Eio_Model_Data *child_pd;
580 _Eio_Children_Slice_Promise* p; 840 Eina_File_Type type;
581 Efl_Promise *promise;
582 Eina_List* li;
583
584 EINA_SAFETY_ON_NULL_RETURN(priv);
585 841
586 eio_file_cancel(priv->listing_file); 842 child_pd = efl_data_scope_get(child, MY_CLASS);
587 priv->listing_file = NULL; 843 if (!child_pd->info) goto on_error;
588 priv->is_listed = EINA_TRUE; 844 if (child_pd->error) goto on_error;
589 priv->is_listing = EINA_FALSE;
590 845
591 _eio_model_efl_model_monitor_add(priv); 846 type = child_pd->info->type;
592 847
593 EINA_LIST_FOREACH(priv->count_promises, li, promise) 848 if (type == EINA_FILE_UNKNOWN)
594 { 849 {
595 unsigned int *c = calloc(1, sizeof(unsigned int)); 850 child_pd->delete_me = EINA_TRUE;
596 *c = eina_list_count(priv->children_list); 851 _eio_build_st(child, child_pd);
597 efl_promise_value_set(promise, c, free); 852 return ;
598 } 853 }
599 eina_list_free(priv->count_promises);
600 priv->count_promises = NULL;
601 854
602 EINA_LIST_FOREACH(priv->children_promises, li, p) 855 efl_ref(child);
856 if (type == EINA_FILE_DIR)
603 { 857 {
604 Eina_Accessor* accessor = efl_model_list_slice(priv->children_list, p->start, p->count); 858 child_pd->request.del = eio_dir_unlink(child_pd->path,
605 efl_promise_value_set(p->promise, accessor, (Eina_Free_Cb)&eina_accessor_free); 859 NULL,
606 free(p); 860 NULL,
861 _eio_done_unlink_cb,
862 _eio_error_unlink_cb,
863 child);
607 } 864 }
608 865 else
609 eina_list_free(priv->children_promises);
610 priv->children_promises = NULL;
611}
612
613static void
614_eio_error_children_load_cb(void *data, Eio_File *handler EINA_UNUSED, int error)
615{
616 Eio_Model_Data *priv = data;
617 _Eio_Children_Slice_Promise* p;
618 Efl_Promise *promise;
619 Eo *child;
620
621 WRN("%d: %s.", error, strerror(error));
622
623 EINA_LIST_FREE(priv->children_list, child)
624 efl_unref(child);
625 priv->children_list = NULL;
626
627 EINA_LIST_FREE(priv->count_promises, promise)
628 efl_promise_failed_set(promise, EFL_MODEL_ERROR_UNKNOWN);
629 priv->count_promises = NULL;
630
631 EINA_LIST_FREE(priv->children_promises, p)
632 { 866 {
633 efl_promise_failed_set(p->promise, EFL_MODEL_ERROR_UNKNOWN); 867 child_pd->request.del = eio_file_unlink(child_pd->path,
634 free(p); 868 _eio_done_unlink_cb,
869 _eio_error_unlink_cb,
870 child);
635 } 871 }
636 priv->children_promises = NULL;
637}
638 872
639static void 873 return ;
640_eio_model_children_filter_set(Eo *obj EINA_UNUSED, Eio_Model_Data *priv, Eio_Filter_Direct_Cb filter_cb, void *data)
641{
642 eina_spinlock_take(&priv->filter_lock);
643
644 priv->filter_cb = filter_cb;
645 priv->filter_userdata = data;
646 874
647 eina_spinlock_release(&priv->filter_lock); 875 on_error:
876 efl_del(child);
648} 877}
649 878
650/** 879/**
651 * Child Add 880 * Children Slice Get
652 */ 881 */
653static Eo * 882static Eina_Future *
654_eio_model_efl_model_child_add(Eo *obj EINA_UNUSED, Eio_Model_Data *priv EINA_UNUSED) 883_eio_model_efl_model_children_slice_get(Eo *obj, Eio_Model_Data *pd,
884 unsigned int start, unsigned int count)
655{ 885{
656 return efl_add(EIO_MODEL_CLASS, obj); 886 Eina_Future_Scheduler *scheduler = NULL;
657} 887 Eina_Value array = EINA_VALUE_EMPTY;
658 888 Eina_List *ls = NULL;
659static void
660_eio_model_efl_model_child_del_stat(void* data, Eio_File* handler EINA_UNUSED, const Eina_Stat* stat)
661{
662 Eo* child = data;
663 Eio_Model_Data *child_priv = efl_data_scope_get(child, MY_CLASS);
664
665 if(eio_file_is_dir(stat))
666 eio_dir_unlink(child_priv->path,
667 _eio_filter_child_del_cb,
668 _eio_progress_child_del_cb,
669 _eio_done_unlink_cb,
670 _eio_error_unlink_cb,
671 child_priv);
672 else
673 eio_file_unlink(child_priv->path, _eio_done_unlink_cb, _eio_error_unlink_cb, child_priv);
674}
675 889
676/** 890 // If called on an invalidated model, we won't have a scheduler
677 * Child Remove 891 scheduler = efl_loop_future_scheduler_get(obj);
678 */ 892 if (!scheduler) return NULL;
679static void
680_eio_model_efl_model_child_del(Eo *obj EINA_UNUSED, Eio_Model_Data *priv, Eo *child)
681{
682 Eio_Model_Data *child_priv;
683 EINA_SAFETY_ON_NULL_RETURN(child);
684 893
685 child_priv = efl_data_scope_get(child, MY_CLASS); 894 // Children must have been listed first
686 EINA_SAFETY_ON_NULL_RETURN(child_priv); 895 if (count == 0 || (start + count > eina_list_count(pd->files)))
896 return eina_future_rejected(scheduler, EFL_MODEL_ERROR_INCORRECT_VALUE);
687 897
688 priv->del_file = eio_file_direct_stat(child_priv->path, 898 eina_value_array_setup(&array, EINA_VALUE_TYPE_OBJECT, count % 8);
689 &_eio_model_efl_model_child_del_stat,
690 &_eio_error_unlink_cb,
691 child);
692 efl_ref(child);
693}
694 899
695/** 900 ls = eina_list_nth_list(pd->files, start);
696 * Children Slice Get
697 */
698static Efl_Future*
699_eio_model_efl_model_children_slice_get(Eo *obj EINA_UNUSED, Eio_Model_Data *priv,
700 unsigned int start, unsigned int count)
701{
702 Eo *loop = efl_provider_find(obj, EFL_LOOP_CLASS);
703 Efl_Promise *promise = efl_add(EFL_PROMISE_CLASS, loop);
704 Efl_Future* future = efl_promise_future_get(promise);
705 /**
706 * children must be already loaded otherwise we do nothing
707 * and parameter is set to NULL.
708 */
709 if (!priv->path)
710 {
711 efl_promise_failed_set(promise, EFL_MODEL_ERROR_INIT_FAILED);
712 return future;
713 }
714 901
715 if (!(priv->is_listed)) 902 while (count > 0)
716 { 903 {
717 _Eio_Children_Slice_Promise* p = calloc(1, sizeof(struct _Eio_Children_Slice_Promise)); 904 Eio_Model_Info *info = eina_list_data_get(ls);
718 p->promise = promise; 905 Eio_Model_Data *child_data = NULL;
719 p->start = start; 906
720 p->count = count; 907 info->child_ref = EINA_TRUE;
721 908
722 priv->children_promises = eina_list_prepend(priv->children_promises, p); 909 if (info->object == NULL)
723 910 // Little trick here, setting internal data before finalize
724 911 info->object = efl_add(EIO_MODEL_CLASS, obj,
725 if (priv->is_listing == EINA_FALSE) 912 child_data = efl_data_scope_get(efl_added, EIO_MODEL_CLASS),
726 { 913 child_data->info = info,
727 priv->is_listing = EINA_TRUE; 914 child_data->path = eina_stringshare_ref(info->path),
728 eio_file_direct_ls(priv->path, _eio_filter_children_load_cb, 915 child_data->parent = ls,
729 _eio_main_children_load_cb, _eio_done_children_load_cb, 916 // NOTE: We are assuming here that the parent model will outlive all its children
730 _eio_error_children_load_cb, priv); 917 child_data->filter.cb = pd->filter.cb,
731 } 918 child_data->filter.data = pd->filter.data);
732 return future; 919 eina_value_array_append(&array, info->object);
920
921 count--;
922 ls = eina_list_next(ls);
733 } 923 }
734 924
735 Eina_Accessor* accessor = efl_model_list_slice(priv->children_list, start, count); 925 return eina_future_resolved(scheduler, array);
736 efl_promise_value_set(promise, accessor, (Eina_Free_Cb)&eina_accessor_free);
737 return future;
738} 926}
739 927
740 928
741/** 929/**
742 * Class definitions 930 * Class definitions
743 */ 931 */
744static Eo * 932static Efl_Object *
745_eio_model_efl_object_constructor(Eo *obj, Eio_Model_Data *priv) 933_eio_model_efl_object_finalize(Eo *obj, Eio_Model_Data *pd)
746{ 934{
747 obj = efl_constructor(efl_super(obj, MY_CLASS)); 935 if (!pd->path) return NULL;
748 unsigned int i; 936
749 priv->obj = obj; 937 // If we have no info at all, let's check this path first
750 priv->is_listed = priv->is_listing = EINA_FALSE; 938 if (!pd->info) _eio_build_st(obj, pd);
751 939
752 priv->properties_name = eina_array_new(EIO_MODEL_PROP_LAST); 940 // Setup monitor
753 EINA_SAFETY_ON_NULL_RETURN_VAL(priv->properties_name, NULL); 941 pd->mon.mon_event_child_add[0] = EIO_MONITOR_DIRECTORY_CREATED;
754 for (i = 0; i < EIO_MODEL_PROP_LAST; ++i) 942 pd->mon.mon_event_child_add[1] = EIO_MONITOR_FILE_CREATED;
755 eina_array_push(priv->properties_name, _eio_model_prop_names[i]); 943 pd->mon.mon_event_child_add[2] = EIO_MONITOR_ERROR;
944 pd->mon.mon_event_child_del[0] = EIO_MONITOR_DIRECTORY_DELETED;
945 pd->mon.mon_event_child_del[1] = EIO_MONITOR_FILE_DELETED;
946 pd->mon.mon_event_child_del[2] = EIO_MONITOR_ERROR;
756 947
757 priv->monitor = NULL; 948 pd->self = obj;
758 eina_spinlock_new(&priv->filter_lock);
759 949
760 return obj; 950 return obj;
761} 951}
@@ -763,70 +953,66 @@ _eio_model_efl_object_constructor(Eo *obj, Eio_Model_Data *priv)
763static void 953static void
764_eio_model_path_set(Eo *obj EINA_UNUSED, Eio_Model_Data *priv, const char *path) 954_eio_model_path_set(Eo *obj EINA_UNUSED, Eio_Model_Data *priv, const char *path)
765{ 955{
766 priv->path = eina_stringshare_add(path); 956 char *sanitized = eina_file_path_sanitize(path);
767 _eio_monitors_list_load(priv); 957 priv->path = eina_stringshare_add(sanitized);
958 free(sanitized);
959}
960
961static const char *
962_eio_model_path_get(const Eo *obj EINA_UNUSED, Eio_Model_Data *priv)
963{
964 return priv->path;
768} 965}
769 966
770static void 967static void
771_eio_model_efl_object_destructor(Eo *obj , Eio_Model_Data *priv) 968_eio_model_efl_object_destructor(Eo *obj , Eio_Model_Data *priv)
772{ 969{
773 Efl_Promise *p; 970 Eio_Model_Info *info;
774 Eo *child;
775 971
776 if (priv->fetching_mime) 972 _eio_model_info_free(priv->info, EINA_TRUE);
777 efl_event_callback_del(efl_provider_find(obj, EFL_LOOP_CLASS), 973 priv->info = NULL;
778 EFL_LOOP_EVENT_IDLE_ENTER, _on_idle_mime, priv);
779 974
780 EINA_LIST_FREE(priv->fetching_mime, p) 975 EINA_LIST_FREE(priv->files, info)
781 { 976 _eio_model_info_free(info, EINA_FALSE);
782 efl_promise_failed_set(p, EINA_ERROR_FUTURE_CANCEL);
783 efl_del(p);
784 }
785
786 _eio_model_efl_model_monitor_del(priv);
787
788 eina_spinlock_free(&priv->filter_lock);
789
790 if (priv->properties_name)
791 eina_array_free(priv->properties_name);
792
793 EINA_LIST_FREE(priv->children_list, child)
794 efl_unref(child);
795 977
796 eina_stringshare_del(priv->path); 978 eina_stringshare_del(priv->path);
979
797 efl_destructor(efl_super(obj, MY_CLASS)); 980 efl_destructor(efl_super(obj, MY_CLASS));
798} 981}
799 982
800static Eo * 983static void
801_eio_model_efl_object_parent_get(const Eo *obj , Eio_Model_Data *priv) 984_eio_model_efl_object_invalidate(Eo *obj , Eio_Model_Data *priv)
802{ 985{
803 Eo *model = efl_parent_get(efl_super(obj, MY_CLASS)); 986 _eio_model_efl_model_monitor_del(priv);
804 987
805 if (model == NULL || !efl_isa(model, EFL_MODEL_INTERFACE)) 988 // Unlink the object from the parent
989 if (priv->info) priv->info->object = NULL;
990 if (priv->request.del)
806 { 991 {
807 char *path = ecore_file_dir_get(priv->path); 992 if (!ecore_thread_wait(priv->request.del->thread, 0.1))
808 if (path != NULL && strcmp(priv->path, "/") != 0)
809 { 993 {
810 model = efl_add_ref(MY_CLASS, NULL, eio_model_path_set(efl_added, path)); 994 ecore_thread_cancel(priv->request.del->thread);
995 ecore_thread_wait(priv->request.del->thread, 0.1);
996 }
997 }
998 if (priv->request.move)
999 {
1000 if (!ecore_thread_wait(priv->request.move->thread, 0.1))
1001 {
1002 ecore_thread_cancel(priv->request.move->thread);
1003 ecore_thread_wait(priv->request.move->thread, 0.1);
1004 }
1005 }
1006 if (priv->request.stat)
1007 {
1008 if (!ecore_thread_wait(priv->request.stat->thread, 0.1))
1009 {
1010 ecore_thread_cancel(priv->request.stat->thread);
1011 ecore_thread_wait(priv->request.stat->thread, 0.1);
811 } 1012 }
812 else
813 model = NULL;
814
815 free(path);
816 } 1013 }
817 return model;
818}
819
820EOLIAN static Eo *
821_eio_model_efl_object_provider_find(const Eo *obj, Eio_Model_Data *priv EINA_UNUSED, const Efl_Class *klass)
822{
823 Eo *provider = efl_provider_find(efl_super(obj, MY_CLASS), klass);
824
825 // Provide main loop even if we don't have a loop user parent
826 if (!provider && (klass == EFL_LOOP_CLASS) && eina_main_loop_is())
827 return efl_main_loop_get();
828 1014
829 return provider; 1015 efl_invalidate(efl_super(obj, EIO_MODEL_CLASS));
830} 1016}
831 1017
832#include "eio_model.eo.c" 1018#include "eio_model.eo.c"