1 /*
2 * TODO:
3 * - child elements focusing support
4 * - user defined icon/label cb
5 * - show/hide/add buttons ???
6 * - Pattern Filter support
7 */
8 #ifdef HAVE_CONFIG_H
9 # include "elementary_config.h"
10 #endif
11
12 #define EFL_ACCESS_OBJECT_PROTECTED
13 #define EFL_ACCESS_WIDGET_ACTION_PROTECTED
14 #define EFL_PART_PROTECTED
15 #define EFL_UI_FOCUS_COMPOSITION_PROTECTED
16
17 #include "elm_priv.h"
18 #include "eo_internal.h"
19 #include <Elementary.h>
20 #include "Eio_Eo.h"
21 #include "elm_fileselector_button_eo.h"
22 #include "elm_fileselector_entry_eo.h"
23 #include "elm_interface_fileselector.h"
24 #include "elm_widget_fileselector.h"
25 #include "elm_entry_eo.h"
26 #include "elm_fileselector_eo.h"
27 #include "elm_genlist_eo.h"
28 #include "elm_gengrid_eo.h"
29
30 #include "elm_fileselector_part.eo.h"
31 #include "elm_part_helper.h"
32
33 #define MY_CLASS ELM_FILESELECTOR_CLASS
34
35 #define MY_CLASS_NAME "Elm_Fileselector"
36 #define MY_CLASS_NAME_LEGACY "elm_fileselector"
37
38 /* FIXME: need a way to find a gap between the size of item and thumbnail */
39 #define ITEM_SIZE_DEFAULT 70
40
41 typedef struct _Legacy_Event_Path_Then_Data
42 {
43 Eo *eo_obj;
44 const Efl_Event_Description *evt_desc;
45 } Legacy_Event_Path_Then_Data;
46
47 static Elm_Genlist_Item_Class *list_itc[ELM_FILE_LAST];
48 static Elm_Gengrid_Item_Class *grid_itc[ELM_FILE_LAST];
49
50 EAPI Eina_Error ELM_FILESELECTOR_ERROR_UNKNOWN = 0;
51 EAPI Eina_Error ELM_FILESELECTOR_ERROR_INVALID_MODEL = 0;
52
53 static const char ELM_FILESELECTOR_ERROR_UNKNOWN_STR[] = "Unknown Error";
54 static const char ELM_FILESELECTOR_ERROR_INVALID_MODEL_STR[] = "Model not set";
55
56 #define ELM_PRIV_FILESELECTOR_SIGNALS(cmd) \
57 cmd(SIG_ACTIVATED, "activated", "s") \
58 cmd(SIG_DIRECTORY_OPEN, "directory,open", "s") \
59 cmd(SIG_DONE, "done", "s") \
60 cmd(SIG_SELECTED, "selected", "s") \
61 cmd(SIG_SELECTED_INVALID, "selected,invalid", "s")
62
63 ELM_PRIV_FILESELECTOR_SIGNALS(ELM_PRIV_STATIC_VARIABLE_DECLARE);
64
65 static const Evas_Smart_Cb_Description _smart_callbacks[] = {
66 ELM_PRIV_FILESELECTOR_SIGNALS(ELM_PRIV_SMART_CALLBACKS_DESC)
67 {SIG_LAYOUT_FOCUSED, ""}, /**< handled by elm_layout */
68 {SIG_LAYOUT_UNFOCUSED, ""}, /**< handled by elm_layout */
69 {NULL, NULL}
70 };
71 #undef ELM_PRIV_FILESELECTOR_SIGNALS
72
73 static Eina_Bool _key_action_select(Evas_Object *obj, const char *params);
74 static Eina_Bool _key_action_escape(Evas_Object *obj, const char *params);
75 static Eina_Bool _key_action_backspace(Evas_Object *obj, const char *params);
76
77 static const Elm_Action key_actions[] = {
78 {"select", _key_action_select},
79 {"escape", _key_action_escape},
80 {"backspace", _key_action_backspace},
81 {NULL, NULL}
82 };
83
84 static void _ok(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED);
85 static void _canc(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED);
86 static void _on_dir_up(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED);
87 static void _populate(Evas_Object *obj, Efl_Model *model, Elm_Object_Item *parent_it, Efl_Model *selected);
88 static Elm_Fileselector_Item_Data *_selected_item_data_get(Elm_Fileselector_Data *sd);
89
90 static void _resource_created(void *, const Efl_Event *);
91 static void _resource_deleted(void *, const Efl_Event *);
92 static void _listing_request_cleanup(Listing_Request *);
93 static void _properties_ready(void *data, const Efl_Event *ev);
94
95 EFL_CALLBACKS_ARRAY_DEFINE(monitoring_callbacks,
96 { EFL_MODEL_EVENT_CHILD_ADDED, _resource_created },
97 { EFL_MODEL_EVENT_CHILD_REMOVED, _resource_deleted });
98
99 static void
_focus_chain_update(Eo * obj,Elm_Fileselector_Data * pd)100 _focus_chain_update(Eo *obj, Elm_Fileselector_Data *pd)
101 {
102 Eina_List *tmp = NULL;
103
104 #define A(p) if (p) tmp = eina_list_append(tmp, p);
105
106 A(pd->up_button)
107 A(pd->home_button)
108 A(pd->search_entry)
109 A(pd->files_view)
110 A(pd->path_entry)
111 A(pd->name_entry)
112 A(pd->filter_hoversel)
113 A(pd->ok_button)
114 A(pd->cancel_button)
115
116
117 #undef A
118
119 efl_ui_focus_composition_elements_set(obj, tmp);
120 }
121
122 void
_event_to_legacy_call(Eo * obj,const char * legacy_evt,void * event_info)123 _event_to_legacy_call(Eo *obj, const char *legacy_evt, void *event_info)
124 {
125 const Efl_Event_Description *legacy_desc = efl_object_legacy_only_event_description_get(legacy_evt);
126 efl_event_callback_call(obj, legacy_desc, event_info);
127 }
128
129 void
_model_event_call(Eo * obj,const Efl_Event_Description * evt_desc,const char * legacy_evt,Efl_Model * model,const char * path)130 _model_event_call(Eo *obj, const Efl_Event_Description *evt_desc, const char *legacy_evt, Efl_Model *model, const char *path)
131 {
132 _event_to_legacy_call(obj, legacy_evt, (void *)path);
133 efl_event_callback_call(obj, evt_desc, model);
134 }
135
136 static void
_monitoring_start(Elm_Fileselector * fs,Elm_Fileselector_Data * sd,Efl_Model * model)137 _monitoring_start(Elm_Fileselector *fs, Elm_Fileselector_Data *sd, Efl_Model *model)
138 {
139 if (sd->monitoring) return ;
140 sd->monitoring = EINA_TRUE;
141 efl_event_callback_array_add(model, monitoring_callbacks(), fs);
142 }
143
144 static void
_monitoring_stop(Elm_Fileselector * fs,Elm_Fileselector_Data * sd,Efl_Model * model)145 _monitoring_stop(Elm_Fileselector *fs, Elm_Fileselector_Data *sd, Efl_Model *model)
146 {
147 if (!sd->monitoring) return ;
148 sd->monitoring = EINA_FALSE;
149 efl_event_callback_array_del(model, monitoring_callbacks(), fs);
150 }
151
152 static void _noref_death(void *data EINA_UNUSED, const Efl_Event *event);
153 static void _invalidated(void *data EINA_UNUSED, const Efl_Event *event);
154
155 EFL_CALLBACKS_ARRAY_DEFINE(noref_death,
156 { EFL_EVENT_NOREF, _noref_death },
157 { EFL_EVENT_INVALIDATE, _invalidated });
158
159 static void
_noref_death(void * data EINA_UNUSED,const Efl_Event * event)160 _noref_death(void *data EINA_UNUSED, const Efl_Event *event)
161 {
162 efl_event_callback_array_del(event->object, noref_death(), NULL);
163 efl_del(event->object);
164 }
165
166 static void
_invalidated(void * data EINA_UNUSED,const Efl_Event * event)167 _invalidated(void *data EINA_UNUSED, const Efl_Event *event)
168 {
169 // This means our parent is dying, EFL_EVENT_NOREF can be called after invalidated
170 efl_event_callback_array_del(event->object, noref_death(), NULL);
171 }
172
173 static void
_reset_target(Elm_Fileselector_Data * pd)174 _reset_target(Elm_Fileselector_Data *pd)
175 {
176 efl_event_callback_del(pd->target, EFL_MODEL_EVENT_PROPERTIES_CHANGED, _properties_ready, pd->obj);
177 efl_replace(&pd->target, NULL);
178 }
179
180 static void
_elm_fileselector_replace_model(Elm_Fileselector * fs,Elm_Fileselector_Data * sd,Efl_Model * model,const char * path)181 _elm_fileselector_replace_model(Elm_Fileselector *fs, Elm_Fileselector_Data *sd, Efl_Model *model, const char *path)
182 {
183 _monitoring_stop(fs, sd, sd->model);
184
185 efl_replace(&sd->model, model);
186 eina_stringshare_replace(&sd->path, path);
187
188 if (model && path)
189 {
190 _monitoring_start(fs, sd, sd->model);
191 /* TODO: sub directory should be monitored for expand mode */
192 }
193 }
194
195 static const char *
_io_path_get(Efl_Model * model)196 _io_path_get(Efl_Model *model)
197 {
198 if (!model) return NULL;
199 if (efl_isa(model, EFL_IO_MODEL_CLASS)) return efl_io_model_path_get(model);
200 return _io_path_get(efl_ui_view_model_get(model));
201 }
202
203 static Eina_Bool
_check_again(Eina_Value * fetch)204 _check_again(Eina_Value *fetch)
205 {
206 Eina_Error err = 0;
207 char *str;
208
209 if (eina_value_type_get(fetch) != EINA_VALUE_TYPE_ERROR)
210 return EINA_FALSE;
211
212 eina_value_error_get(fetch, &err);
213 if (err == EAGAIN) return EINA_TRUE;
214
215 str = eina_value_to_string(fetch);
216 ERR("Unexpected error: '%s'.", str);
217 free(str);
218
219 return EINA_TRUE;
220 }
221
222 static Eina_Bool
_fetch_string_value(Efl_Model * child,const char * name,char ** str)223 _fetch_string_value(Efl_Model *child, const char *name, char **str)
224 {
225 Eina_Value *fetch;
226 Eina_Bool r = EINA_FALSE;
227
228 *str = NULL;
229
230 fetch = efl_model_property_get(child, name);
231 if (_check_again(fetch)) goto on_error;
232
233 *str = eina_value_to_string(fetch);
234 r = EINA_TRUE;
235
236 on_error:
237 eina_value_free(fetch);
238 return r;
239 }
240
241 static Eina_Bool
_fetch_bool_value(Efl_Model * child,const char * name,Eina_Bool * b)242 _fetch_bool_value(Efl_Model *child, const char *name, Eina_Bool *b)
243 {
244 Eina_Value *fetch;
245 Eina_Bool r = EINA_FALSE;
246
247 fetch = efl_model_property_get(child, name);
248 if (_check_again(fetch)) goto on_error;
249 if (!eina_value_bool_get(fetch, b)) goto on_error;
250
251 r = EINA_TRUE;
252
253 on_error:
254 eina_value_free(fetch);
255 return r;
256 }
257
258 static Eina_Bool
_fetch_double_value(Efl_Model * child,const char * name,double * d)259 _fetch_double_value(Efl_Model *child, const char *name, double *d)
260 {
261 Eina_Value convert = EINA_VALUE_EMPTY;
262 Eina_Value *fetch;
263 Eina_Bool r = EINA_FALSE;
264
265 fetch = efl_model_property_get(child, name);
266 if (_check_again(fetch)) goto on_error;
267 if (!eina_value_setup(&convert, EINA_VALUE_TYPE_DOUBLE))
268 goto on_error;
269 if (!eina_value_convert(fetch, &convert))
270 goto on_error;
271 if (!eina_value_double_get(&convert, d)) goto on_error;
272
273 r = EINA_TRUE;
274
275 on_error:
276 eina_value_flush(&convert);
277 eina_value_free(fetch);
278 return r;
279 }
280
281 static Eina_Bool
_fetch_int64_value(Efl_Model * child,const char * name,int64_t * i)282 _fetch_int64_value(Efl_Model *child, const char *name, int64_t *i)
283 {
284 Eina_Value convert = EINA_VALUE_EMPTY;
285 Eina_Value *fetch;
286 Eina_Bool r = EINA_FALSE;
287
288 fetch = efl_model_property_get(child, name);
289 if (_check_again(fetch)) goto on_error;
290 if (!eina_value_setup(&convert, EINA_VALUE_TYPE_INT64))
291 goto on_error;
292 if (!eina_value_convert(fetch, &convert))
293 goto on_error;
294 if (!eina_value_int64_get(&convert, i)) goto on_error;
295
296 r = EINA_TRUE;
297
298 on_error:
299 eina_value_free(fetch);
300 return r;
301 }
302
303 /* final routine on deletion */
304 static void
_elm_fileselector_smart_del_do(Elm_Fileselector * fs,Elm_Fileselector_Data * sd)305 _elm_fileselector_smart_del_do(Elm_Fileselector *fs, Elm_Fileselector_Data *sd)
306 {
307 Eo *child;
308 EINA_LIST_FREE(sd->children, child)
309 efl_unref(child);
310 _elm_fileselector_replace_model(fs, sd, NULL, NULL);
311 efl_replace(&sd->prev_model, NULL);
312 ecore_idler_del(sd->path_entry_idler);
313
314 efl_canvas_group_del(efl_super(sd->obj, MY_CLASS));
315 }
316
317 static void
_mirrored_set(Evas_Object * obj,Eina_Bool rtl)318 _mirrored_set(Evas_Object *obj, Eina_Bool rtl)
319 {
320 ELM_FILESELECTOR_DATA_GET(obj, sd);
321
322 efl_ui_mirrored_set(sd->cancel_button, rtl);
323 efl_ui_mirrored_set(sd->ok_button, rtl);
324 efl_ui_mirrored_set(sd->files_view, rtl);
325 efl_ui_mirrored_set(sd->up_button, rtl);
326 efl_ui_mirrored_set(sd->home_button, rtl);
327 }
328
329 EOLIAN static Eina_Error
_elm_fileselector_efl_ui_widget_theme_apply(Eo * obj,Elm_Fileselector_Data * sd)330 _elm_fileselector_efl_ui_widget_theme_apply(Eo *obj, Elm_Fileselector_Data *sd)
331 {
332 const char *style;
333 const char *data;
334 char buf[1024];
335 Eina_Error int_ret = EFL_UI_THEME_APPLY_ERROR_GENERIC;
336
337 int_ret = efl_ui_widget_theme_apply(efl_super(obj, MY_CLASS));
338 if (int_ret == EFL_UI_THEME_APPLY_ERROR_GENERIC) return int_ret;
339
340 if (!efl_finalized_get(obj)) return int_ret;
341 style = elm_widget_style_get(obj);
342 _mirrored_set(obj, efl_ui_mirrored_get(obj));
343
344 ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd, EINA_FALSE);
345
346 data = edje_object_data_get
347 (wd->resize_obj, "path_separator");
348 if (data) sd->path_separator = data;
349 else sd->path_separator = "/";
350
351 snprintf(buf, sizeof(buf), "fileselector/%s", style);
352
353 elm_widget_style_set(sd->up_button, buf);
354 elm_widget_style_set(sd->home_button, buf);
355 elm_widget_style_set(sd->spinner, buf);
356
357 elm_widget_style_set(sd->files_view, buf);
358
359 elm_widget_style_set(sd->path_entry, buf);
360 elm_widget_style_set(sd->name_entry, buf);
361 elm_widget_style_set(sd->search_entry, buf);
362
363 snprintf(buf, sizeof(buf), "fileselector/actions/%s", style);
364
365 if (sd->filter_hoversel)
366 elm_widget_style_set(sd->filter_hoversel, buf);
367
368 if (sd->ok_button)
369 {
370 elm_widget_style_set(sd->cancel_button, buf);
371 elm_widget_style_set(sd->ok_button, buf);
372 }
373
374 return int_ret;
375 }
376
377 static Eina_Bool
_key_action_select(Evas_Object * obj,const char * params EINA_UNUSED)378 _key_action_select(Evas_Object *obj, const char *params EINA_UNUSED)
379 {
380 _ok(obj, NULL, NULL);
381 return EINA_TRUE;
382 }
383
384 static Eina_Bool
_key_action_escape(Evas_Object * obj,const char * params EINA_UNUSED)385 _key_action_escape(Evas_Object *obj, const char *params EINA_UNUSED)
386 {
387 _canc(obj, NULL, NULL);
388 return EINA_TRUE;
389 }
390
391 static Eina_Bool
_key_action_backspace(Evas_Object * obj,const char * params EINA_UNUSED)392 _key_action_backspace(Evas_Object *obj, const char *params EINA_UNUSED)
393 {
394 ELM_FILESELECTOR_DATA_GET(obj, sd);
395 if (sd->prev_model)
396 {
397 Efl_Model *tmp = NULL;
398
399 tmp = sd->prev_model;
400 sd->prev_model = NULL;
401 _populate(obj, sd->prev_model, NULL, NULL);
402 efl_unref(tmp);
403 }
404 else
405 _on_dir_up(obj, NULL, NULL);
406
407 return EINA_TRUE;
408 }
409
410 /*** GENLIST/GENGRID "MODEL" ***/
411 static char *
_itc_text_get(void * data,Evas_Object * obj EINA_UNUSED,const char * source EINA_UNUSED)412 _itc_text_get(void *data,
413 Evas_Object *obj EINA_UNUSED,
414 const char *source EINA_UNUSED)
415 {
416 Elm_Fileselector_Item_Data *it_data = data;
417 return elm_entry_utf8_to_markup
418 (it_data->filename); /* NOTE this will be free()'d by
419 * the caller */
420 }
421
422 static Evas_Object *
_itc_icon_folder_get(void * data EINA_UNUSED,Evas_Object * obj,const char * source)423 _itc_icon_folder_get(void *data EINA_UNUSED,
424 Evas_Object *obj,
425 const char *source)
426 {
427 Evas_Object *ic, *grid;
428
429 if (strcmp(source, "elm.swallow.icon")) return NULL;
430
431 ic = elm_icon_add(obj);
432 elm_icon_standard_set(ic, "folder");
433 evas_object_size_hint_aspect_set(ic, EVAS_ASPECT_CONTROL_VERTICAL, 1, 1);
434 evas_object_show(ic);
435
436 grid = elm_grid_add(obj);
437 elm_grid_size_set(grid, 1, 1);
438 elm_grid_pack(grid, ic, 0, 0, 1, 1);
439 evas_object_show(grid);
440
441 return grid;
442 }
443
444 static Evas_Object *
_itc_icon_image_get(void * data,Evas_Object * obj,const char * source)445 _itc_icon_image_get(void *data,
446 Evas_Object *obj,
447 const char *source)
448 {
449 Elm_Fileselector_Item_Data *it_data = data;
450 Evas_Object *ic, *grid;
451
452 if (strcmp(source, "elm.swallow.icon")) return NULL;
453
454 ic = elm_icon_add(obj);
455 elm_icon_standard_set(ic, "image");
456 // FIXME: maybe use Efl.Model.connect
457 elm_icon_thumb_set(ic, it_data->path, NULL);
458 evas_object_size_hint_aspect_set(ic, EVAS_ASPECT_CONTROL_VERTICAL, 1, 1);
459 evas_object_show(ic);
460
461 grid = elm_grid_add(obj);
462 elm_grid_size_set(grid, 1, 1);
463 elm_grid_pack(grid, ic, 0, 0, 1, 1);
464 evas_object_show(grid);
465
466 return grid;
467 }
468
469 static Evas_Object *
_itc_icon_file_get(void * data EINA_UNUSED,Evas_Object * obj,const char * source)470 _itc_icon_file_get(void *data EINA_UNUSED,
471 Evas_Object *obj,
472 const char *source)
473 {
474 Evas_Object *ic, *grid;
475
476 if (strcmp(source, "elm.swallow.icon")) return NULL;
477
478 ic = elm_icon_add(obj);
479 elm_icon_standard_set(ic, "file");
480 evas_object_size_hint_aspect_set(ic, EVAS_ASPECT_CONTROL_VERTICAL, 1, 1);
481 evas_object_show(ic);
482
483 grid = elm_grid_add(obj);
484 elm_grid_size_set(grid, 1, 1);
485 elm_grid_pack(grid, ic, 0, 0, 1, 1);
486 evas_object_show(grid);
487
488 return grid;
489 }
490
491 static Eina_Bool
_itc_state_get(void * data EINA_UNUSED,Evas_Object * obj EINA_UNUSED,const char * source EINA_UNUSED)492 _itc_state_get(void *data EINA_UNUSED,
493 Evas_Object *obj EINA_UNUSED,
494 const char *source EINA_UNUSED)
495 {
496 return EINA_FALSE;
497 }
498
499 static void
_itc_del(void * data,Evas_Object * obj EINA_UNUSED)500 _itc_del(void *data,
501 Evas_Object *obj EINA_UNUSED)
502 {
503 Elm_Fileselector_Item_Data *it_data = data;
504 efl_key_data_set(it_data->model, ".item.data", NULL);
505 efl_unref(it_data->model);
506 eina_stringshare_del(it_data->path);
507 eina_stringshare_del(it_data->filename);
508 eina_stringshare_del(it_data->mime_type);
509 eina_stringshare_del(it_data->parent_path);
510 free(it_data);
511 }
512
513 static void
_anchors_do(Evas_Object * obj,const char * path)514 _anchors_do(Evas_Object *obj,
515 const char *path)
516 {
517 char **tok, buf[PATH_MAX * 3], *s;
518 int i, j;
519
520 ELM_FILESELECTOR_DATA_GET(obj, sd);
521
522 s = elm_entry_utf8_to_markup(path);
523 if (!s) return;
524
525 buf[0] = '\0';
526 tok = eina_str_split(s, "/", 0);
527 free(s);
528
529 eina_strlcat(buf, "<a href='/'>root</a>", sizeof(buf));
530 for (i = 0; tok[i]; i++)
531 {
532 if ((!tok[i]) || (!tok[i][0])) continue;
533 eina_strlcat(buf, sd->path_separator, sizeof(buf));
534 eina_strlcat(buf, "<a href=", sizeof(buf));
535 for (j = 0; j <= i; j++)
536 {
537 if (strlen(tok[j]) < 1) continue;
538 eina_strlcat(buf, "/", sizeof(buf));
539 eina_strlcat(buf, tok[j], sizeof(buf));
540 }
541 eina_strlcat(buf, ">", sizeof(buf));
542 eina_strlcat(buf, tok[i], sizeof(buf));
543 eina_strlcat(buf, "</a>", sizeof(buf));
544 }
545 free(tok[0]);
546 free(tok);
547
548 elm_object_text_set(sd->path_entry, buf);
549 }
550
551 static Eina_Bool
_mime_type_matched(const char * mime_filter,const char * mime_type)552 _mime_type_matched(const char *mime_filter, const char *mime_type)
553 {
554 int i = 0;
555
556 while (mime_filter[i] != '\0')
557 {
558 if (mime_filter[i] != mime_type[i])
559 {
560 if (mime_filter[i] == '*' && mime_filter[i + 1] == '\0')
561 return EINA_TRUE;
562
563 return EINA_FALSE;
564 }
565 i++;
566 }
567
568 if (mime_type[i] != '\0') return EINA_FALSE;
569
570 return EINA_TRUE;
571 }
572
573 static Eina_Bool
_is_in_filter(const Elm_Fileselector_Filter * filter,const char * mime_type)574 _is_in_filter(const Elm_Fileselector_Filter *filter, const char *mime_type)
575 {
576 int i;
577 if (!mime_type) return EINA_FALSE;
578
579 for (i = 0; filter->filter.mime_types[i]; ++i)
580 {
581 if (_mime_type_matched(filter->filter.mime_types[i], mime_type))
582 return EINA_TRUE;
583 }
584 return EINA_FALSE;
585 }
586
587 static Eina_Bool
_filter_child(Elm_Fileselector_Data * sd,const char * path,const char * filename,Eina_Bool dir,const char * mime_type)588 _filter_child(Elm_Fileselector_Data* sd,
589 const char *path,
590 const char *filename,
591 Eina_Bool dir,
592 const char *mime_type)
593 {
594 Elm_Fileselector_Filter *cf;
595 char *pch = NULL, *temp = NULL;
596 char temp_path[EINA_PATH_MAX];
597
598 if (!sd) return EINA_FALSE;
599
600 if (!sd->hidden_visible && filename[0] == '.')
601 return EINA_FALSE;
602
603 if (sd->only_folder && !dir)
604 return EINA_FALSE;
605
606 //Search entry filter
607 if ((sd->search_string) && (sd->search_string[0] != '\0'))
608 {
609 strncpy(temp_path, path, sizeof(temp_path) - 1);
610 temp_path[sizeof(temp_path) - 1] = 0;
611 pch = strchr(temp_path, EINA_PATH_SEP_C);
612 while (pch != NULL)
613 {
614 temp = pch;
615 pch = strchr(pch + 1, EINA_PATH_SEP_C);
616 }
617 temp++;
618 if ((temp) && (sd->search_string) &&
619 (!strstr(temp, sd->search_string)))
620 return EINA_FALSE;
621 }
622
623 cf = sd->current_filter;
624 if (!cf)
625 return EINA_TRUE;
626
627 switch (cf->filter_type)
628 {
629 case ELM_FILESELECTOR_MIME_FILTER:
630 return dir || _is_in_filter(cf, mime_type);
631 case ELM_FILESELECTOR_CUSTOM_FILTER:
632 return cf->filter.custom->func(path, dir,
633 cf->filter.custom->data);
634 default:
635 return EINA_FALSE;
636 }
637
638 return EINA_FALSE;
639 }
640
641 static Eina_Value
_filter_do(Eo * child,void * data,const Eina_Value v EINA_UNUSED)642 _filter_do(Eo *child, void *data, const Eina_Value v EINA_UNUSED)
643 {
644 Elm_Fileselector_Data* sd = data;
645 // FIXME: This could be only needed with ELM_FILESELECTOR_MIME_FILTER
646 char *mime_type = NULL;
647 char *filename = NULL;
648 char *path = NULL;
649 int64_t size = 0;
650 double mtime = 0;
651 Eina_Bool dir = EINA_FALSE;
652 Eina_Bool r = EINA_FALSE;
653
654 if (!_fetch_string_value(child, "path", &path) ||
655 !_fetch_string_value(child, "filename", &filename) ||
656 !_fetch_string_value(child, "mime_type", &mime_type) ||
657 !_fetch_double_value(child, "mtime", &mtime) ||
658 !_fetch_int64_value(child, "size", &size) ||
659 !_fetch_bool_value(child, "is_dir", &dir))
660 goto cleanup;
661
662 if (!path || !filename || !mime_type)
663 {
664 ERR("Wrong file info ('%s', '%s', '%s').", path, filename, mime_type);
665 goto cleanup;
666 }
667
668 if (!_filter_child(sd, path, filename, dir, mime_type))
669 goto cleanup;
670
671 r = EINA_TRUE;
672
673 cleanup:
674 free(mime_type);
675 free(filename);
676 free(path);
677
678 return eina_value_bool_init(r);
679 }
680
681 static void
_filter_free(Eo * o,void * data EINA_UNUSED,const Eina_Future * dead_future EINA_UNUSED)682 _filter_free(Eo *o, void *data EINA_UNUSED, const Eina_Future *dead_future EINA_UNUSED)
683 {
684 efl_unref(o);
685 }
686
687 static Eina_Future *
_filter_simple(void * data,Efl_Filter_Model * parent,Efl_Model * child)688 _filter_simple(void *data, Efl_Filter_Model *parent, Efl_Model *child)
689 {
690 Elm_Fileselector_Data* sd = data;
691 Eina_Future *request[8];
692 Eina_Future *f;
693
694 request[0] = efl_model_property_ready_get(parent, "path");
695 request[1] = efl_model_property_ready_get(child, "path");
696 request[2] = efl_model_property_ready_get(child, "filename");
697 request[3] = efl_model_property_ready_get(child, "mime_type");
698 request[4] = efl_model_property_ready_get(child, "mtime");
699 request[5] = efl_model_property_ready_get(child, "size");
700 request[6] = efl_model_property_ready_get(child, "is_dir");
701 request[7] = EINA_FUTURE_SENTINEL;
702
703 f = eina_future_all_array(request);
704 f = efl_future_then(efl_ref(child), f,
705 .success = _filter_do,
706 .free = _filter_free,
707 .data = sd);
708
709 return f;
710 }
711
712 static const char *
_file_type(const char * a)713 _file_type(const char *a)
714 {
715 char *p = strrchr(a, '.');
716 if (!p) return "";
717
718 return p;
719 }
720
721 static int
_filename_cmp(const Elm_Fileselector_Item_Data * a,const Elm_Fileselector_Item_Data * b)722 _filename_cmp(const Elm_Fileselector_Item_Data *a, const Elm_Fileselector_Item_Data *b)
723 {
724 return strcoll(a->filename, b->filename);
725 }
726
727 static int
_filename_cmp_rev(const Elm_Fileselector_Item_Data * a,const Elm_Fileselector_Item_Data * b)728 _filename_cmp_rev(const Elm_Fileselector_Item_Data *a, const Elm_Fileselector_Item_Data *b)
729 {
730 return _filename_cmp(b, a);
731 }
732
733 static int
_type_cmp(const Elm_Fileselector_Item_Data * a,const Elm_Fileselector_Item_Data * b)734 _type_cmp(const Elm_Fileselector_Item_Data *a, const Elm_Fileselector_Item_Data *b)
735 {
736 return strcoll(_file_type(a->filename), _file_type(b->filename));
737 }
738
739 static int
_type_cmp_rev(const Elm_Fileselector_Item_Data * a,const Elm_Fileselector_Item_Data * b)740 _type_cmp_rev(const Elm_Fileselector_Item_Data *a, const Elm_Fileselector_Item_Data *b)
741 {
742 return _type_cmp(b, a);
743 }
744
745 static int
_size_cmp(const Elm_Fileselector_Item_Data * a,const Elm_Fileselector_Item_Data * b)746 _size_cmp(const Elm_Fileselector_Item_Data *a, const Elm_Fileselector_Item_Data *b)
747 {
748 return a->size - b->size;
749 }
750
751 static int
_size_cmp_rev(const Elm_Fileselector_Item_Data * a,const Elm_Fileselector_Item_Data * b)752 _size_cmp_rev(const Elm_Fileselector_Item_Data *a, const Elm_Fileselector_Item_Data *b)
753 {
754 return _size_cmp(b, a);
755 }
756
757 static int
_modified_cmp(const Elm_Fileselector_Item_Data * a,const Elm_Fileselector_Item_Data * b)758 _modified_cmp(const Elm_Fileselector_Item_Data *a, const Elm_Fileselector_Item_Data *b)
759 {
760 if (a->mtime > b->mtime)
761 return 1;
762
763 return -1;
764 }
765
766 static int
_modified_cmp_rev(const Elm_Fileselector_Item_Data * a,const Elm_Fileselector_Item_Data * b)767 _modified_cmp_rev(const Elm_Fileselector_Item_Data *a, const Elm_Fileselector_Item_Data *b)
768 {
769 return _modified_cmp(b, a);
770 }
771
772 static int
_file_grid_cmp(const void * a,const void * b)773 _file_grid_cmp(const void *a, const void *b)
774 {
775 Evas_Object *f;
776
777 const Elm_Object_Item *ga = a;
778 const Elm_Object_Item *gb = b;
779 const Elm_Gengrid_Item_Class *ca = elm_gengrid_item_item_class_get(ga);
780 const Elm_Gengrid_Item_Class *cb = elm_gengrid_item_item_class_get(gb);
781
782 if (ca == grid_itc[ELM_DIRECTORY])
783 {
784 if (cb != grid_itc[ELM_DIRECTORY])
785 return -1;
786 }
787 else if (cb == grid_itc[ELM_DIRECTORY])
788 {
789 return 1;
790 }
791
792 f = evas_object_data_get(elm_object_item_widget_get(ga), "parent");
793 ELM_FILESELECTOR_DATA_GET(f, sd);
794 return sd->sort_method(elm_object_item_data_get(ga),
795 elm_object_item_data_get(gb));
796 }
797
798 static int
_file_list_cmp(const void * a,const void * b)799 _file_list_cmp(const void *a, const void *b)
800 {
801 Evas_Object *f;
802
803 const Elm_Object_Item *la = a;
804 const Elm_Object_Item *lb = b;
805 const Elm_Genlist_Item_Class *ca = elm_genlist_item_item_class_get(la);
806 const Elm_Genlist_Item_Class *cb = elm_genlist_item_item_class_get(lb);
807
808 if (ca == list_itc[ELM_DIRECTORY])
809 {
810 if (cb != list_itc[ELM_DIRECTORY])
811 return -1;
812 }
813 else if (cb == list_itc[ELM_DIRECTORY])
814 {
815 return 1;
816 }
817
818 f = evas_object_data_get(elm_object_item_widget_get(la), "parent");
819 ELM_FILESELECTOR_DATA_GET(f, sd);
820 return sd->sort_method(elm_object_item_data_get(la),
821 elm_object_item_data_get(lb));
822 }
823
824 static void
_signal_first(Listing_Request * lreq)825 _signal_first(Listing_Request *lreq)
826 {
827 Elm_Fileselector_Data *sd = lreq->sd;
828
829 if (!lreq->first) return;
830 if (!sd) return;
831
832 if (sd->multi)
833 {
834 sd->multi_selection = eina_list_free(sd->multi_selection);
835 }
836
837 _model_event_call(lreq->obj, ELM_FILESELECTOR_EVENT_DIRECTORY_OPEN, ELM_FILESELECTOR_EVENT_DIRECTORY_OPEN->name, lreq->model, lreq->path);
838
839 if (!lreq->parent_it)
840 {
841 if (sd->mode == ELM_FILESELECTOR_LIST)
842 elm_genlist_clear(sd->files_view);
843 else
844 elm_gengrid_clear(sd->files_view);
845 _elm_fileselector_replace_model(lreq->obj, sd, lreq->model, lreq->path);
846 _anchors_do(lreq->obj, lreq->path);
847 }
848
849 lreq->first = EINA_FALSE;
850 }
851
852 static void
_process_last(Listing_Request * lreq)853 _process_last(Listing_Request *lreq)
854 {
855 Elm_Fileselector_Data *sd = lreq->sd;
856
857 if (lreq->valid)
858 {
859 elm_progressbar_pulse(sd->spinner, EINA_FALSE);
860 elm_layout_signal_emit(lreq->obj, "elm,action,spinner,hide", "elm");
861 }
862
863 _listing_request_cleanup(lreq);
864 sd->current_populate_lreq = NULL;
865 }
866
867 static void
_listing_request_cleanup(Listing_Request * lreq)868 _listing_request_cleanup(Listing_Request *lreq)
869 {
870 if (!lreq) return ;
871 if (lreq->parent_it)
872 efl_unref(lreq->parent_it);
873 efl_unref(lreq->obj);
874 efl_unref(lreq->model);
875 if (lreq->selected)
876 efl_unref(lreq->selected);
877 eina_stringshare_del(lreq->path);
878 eina_stringshare_del(lreq->selected_path);
879 free(lreq);
880 }
881
882 static void
_process_model(Elm_Fileselector_Data * sd,Efl_Model * child,Elm_Object_Item * fallback_parent_item)883 _process_model(Elm_Fileselector_Data *sd, Efl_Model *child, Elm_Object_Item *fallback_parent_item)
884 {
885 Elm_Fileselector_Item_Data *it_data;
886 Elm_Object_Item *item, *it_parent;
887 int itcn = ELM_FILE_UNKNOW;
888
889 Efl_Model *parent = efl_parent_get(child);
890 char *parent_path = NULL;
891 // FIXME: This could be only needed with ELM_FILESELECTOR_MIME_FILTER
892 char *mime_type = NULL;
893 char *filename = NULL;
894 char *path = NULL;
895 int64_t size = 0;
896 double mtime = 0;
897 Eina_Bool dir = EINA_FALSE;
898
899 // In case we are shutting down, there might be an error being gnerated
900 if (!parent) return ;
901
902 // We should be good now and already filtered
903 if (!_fetch_string_value(parent, "path", &parent_path) ||
904 !_fetch_string_value(child, "path", &path) ||
905 !_fetch_string_value(child, "filename", &filename) ||
906 !_fetch_string_value(child, "mime_type", &mime_type) ||
907 !_fetch_double_value(child, "mtime", &mtime) ||
908 !_fetch_int64_value(child, "size", &size) ||
909 !_fetch_bool_value(child, "is_dir", &dir))
910 goto cleanup;
911
912 it_data = calloc(1, sizeof(Elm_Fileselector_Item_Data));
913 if (!it_data)
914 {
915 ERR("Not enough memory.");
916 goto cleanup;
917 }
918
919 it_data->model = efl_ref(child);
920 it_data->parent_model = parent;
921 it_data->parent_path = eina_stringshare_add(parent_path);
922 it_data->path = eina_stringshare_add(path);
923 it_data->filename = eina_stringshare_add(filename);
924 it_data->size = size;
925 it_data->mtime = mtime;
926 it_data->mime_type = eina_stringshare_add(mime_type);
927 it_data->is_dir = dir;
928
929 it_parent = efl_key_data_get(parent, ".item.data");
930 if (!it_parent)
931 it_parent = fallback_parent_item;
932
933 if (dir)
934 {
935 itcn = ELM_DIRECTORY;
936 }
937 else
938 {
939 if (evas_object_image_extension_can_load_get(it_data->filename))
940 itcn = ELM_FILE_IMAGE;
941 }
942
943 if (sd->mode == ELM_FILESELECTOR_LIST)
944 item = elm_genlist_item_sorted_insert(sd->files_view, list_itc[itcn],
945 it_data,
946 it_parent,
947 (sd->expand && itcn == ELM_DIRECTORY) ? ELM_GENLIST_ITEM_TREE : ELM_GENLIST_ITEM_NONE,
948 _file_list_cmp, NULL, NULL);
949 else
950 item = elm_gengrid_item_sorted_insert(sd->files_view, grid_itc[itcn],
951 it_data,
952 _file_grid_cmp, NULL, NULL);
953 efl_key_data_set(child, ".item.data", item);
954
955 // Is this item selected
956 if (sd->target && sd->target_ready)
957 {
958 const char *target_path = _io_path_get(sd->target);
959
960 if (!strcmp(it_data->path, target_path))
961 {
962 elm_genlist_item_selected_set(item, EINA_TRUE);
963 elm_object_text_set(sd->name_entry, it_data->filename);
964
965 _reset_target(sd);
966 }
967 }
968
969 cleanup:
970 free(mime_type);
971 free(filename);
972 free(path);
973 free(parent_path);
974 }
975
976 static Eina_Value
_process_children_cb(Eo * model EINA_UNUSED,void * data,const Eina_Value v)977 _process_children_cb(Eo *model EINA_UNUSED, void *data, const Eina_Value v)
978 {
979 Listing_Request *lreq = data;
980 Efl_Model *child = NULL;
981 unsigned int i, len;
982
983 if (!lreq->valid) goto end;
984
985 EINA_VALUE_ARRAY_FOREACH(&v, len, i, child)
986 {
987 _process_model(lreq->sd, child, lreq->parent_it);
988 }
989
990 lreq->item_total = len;
991
992 _signal_first(lreq);
993
994 end:
995 _process_last(lreq);
996
997 return v;
998 }
999
1000 static Eina_Value
_process_children_error(Eo * model EINA_UNUSED,void * data,Eina_Error error)1001 _process_children_error(Eo *model EINA_UNUSED, void *data, Eina_Error error)
1002 {
1003 Listing_Request *lreq = data;
1004
1005 _process_last(lreq);
1006
1007 return eina_value_error_init(error);
1008 }
1009
1010 static void
_count_changed_cb(void * data,const Efl_Event * ev EINA_UNUSED)1011 _count_changed_cb(void *data, const Efl_Event *ev EINA_UNUSED)
1012 {
1013 Listing_Request *lreq = data;
1014 Eina_Future *future;
1015
1016 efl_event_callback_del(lreq->model, EFL_MODEL_EVENT_CHILDREN_COUNT_CHANGED, _count_changed_cb, lreq);
1017
1018 if (efl_model_children_count_get(lreq->model))
1019 {
1020 future = efl_model_children_slice_get(lreq->model, 0, efl_model_children_count_get(lreq->model));
1021 future = efl_future_then(lreq->obj, future);
1022 efl_future_then(lreq->model, future,
1023 .success = _process_children_cb,
1024 .error = _process_children_error,
1025 .data = lreq);
1026 }
1027 else
1028 {
1029 _process_last(lreq);
1030 }
1031 }
1032
1033 static void
_populate(Evas_Object * obj,Efl_Model * model,Elm_Object_Item * parent_it,Efl_Model * selected)1034 _populate(Evas_Object *obj,
1035 Efl_Model *model,
1036 Elm_Object_Item *parent_it,
1037 Efl_Model *selected)
1038 {
1039 ELM_FILESELECTOR_DATA_GET(obj, sd);
1040 Listing_Request *lreq;
1041 Eina_Future *future;
1042 Eina_Value *fetch;
1043 char *string;
1044
1045 if (!model) return;
1046
1047 if (sd->expand && sd->current_populate_lreq)
1048 return;
1049
1050 if (sd->current_populate_lreq)
1051 {
1052 sd->current_populate_lreq->valid = EINA_FALSE;
1053 sd->current_populate_lreq = NULL;
1054 }
1055
1056 if (sd->monitoring)
1057 _monitoring_stop(obj, sd, sd->model);
1058
1059 lreq = calloc(1, sizeof (Listing_Request));
1060 if (!lreq) return;
1061
1062 lreq->sd = sd;
1063 lreq->parent_it = (parent_it ? efl_ref(parent_it) : NULL);
1064 lreq->obj = efl_ref(obj);
1065 if (efl_isa(model, EFL_FILTER_MODEL_CLASS))
1066 model = efl_ui_view_model_get(model);
1067
1068 lreq->model = efl_add_ref(EFL_FILTER_MODEL_CLASS, obj,
1069 efl_ui_view_model_set(efl_added, model),
1070 efl_filter_model_filter_set(efl_added, sd, _filter_simple, NULL),
1071 efl_loop_model_volatile_make(efl_added));
1072 lreq->selected = (selected ? efl_ref(selected) : NULL);
1073 lreq->path = NULL;
1074 lreq->selected_path = NULL;
1075 lreq->item_total = 0;
1076 lreq->item_processed_count = 0;
1077 lreq->first = EINA_TRUE;
1078 lreq->valid = EINA_TRUE;
1079
1080 sd->current_populate_lreq = lreq;
1081
1082 elm_progressbar_pulse(sd->spinner, EINA_TRUE);
1083 elm_layout_signal_emit(lreq->obj, "elm,action,spinner,show", "elm");
1084
1085 // Clear name entry not in case of save mode.
1086 if (elm_object_disabled_get(sd->name_entry))
1087 elm_object_text_set(sd->name_entry, "");
1088
1089 fetch = efl_model_property_get(model, "path");
1090 string = eina_value_to_string(fetch);
1091 lreq->path = eina_stringshare_add(string);
1092 eina_value_free(fetch);
1093 free(string);
1094
1095 if (selected)
1096 {
1097 fetch = efl_model_property_get(selected, "path");
1098 string = eina_value_to_string(fetch);
1099 lreq->selected_path = eina_stringshare_add(string);
1100 eina_value_free(fetch);
1101 free(string);
1102 }
1103
1104 _signal_first(lreq);
1105
1106 if (efl_model_children_count_get(lreq->model))
1107 {
1108 future = efl_model_children_slice_get(lreq->model, 0, efl_model_children_count_get(model));
1109 future = efl_future_then(obj, future);
1110 efl_future_then(lreq->model, future,
1111 .success = _process_children_cb,
1112 .error = _process_children_error,
1113 .data = lreq);
1114 }
1115 else
1116 {
1117 if (parent_it)
1118 efl_event_callback_add(lreq->model, EFL_MODEL_EVENT_CHILDREN_COUNT_CHANGED, _count_changed_cb, lreq);
1119 else
1120 _process_last(lreq);
1121 }
1122 }
1123
1124 static void
_on_list_expanded(void * data,const Efl_Event * event)1125 _on_list_expanded(void *data, const Efl_Event *event)
1126 {
1127 Elm_Object_Item *it = event->info;
1128 const Elm_Fileselector_Item_Data *it_data = elm_object_item_data_get(it);
1129
1130 _populate(data, it_data->model, it, NULL);
1131 }
1132
1133 static void
_on_list_contracted(void * data EINA_UNUSED,const Efl_Event * event)1134 _on_list_contracted(void *data EINA_UNUSED, const Efl_Event *event)
1135 {
1136 Elm_Object_Item *it = event->info;
1137
1138 elm_genlist_item_subitems_clear(it);
1139 }
1140
1141 static void
_on_list_expand_req(void * data EINA_UNUSED,const Efl_Event * event)1142 _on_list_expand_req(void *data EINA_UNUSED, const Efl_Event *event)
1143 {
1144 Elm_Object_Item *it = event->info;
1145
1146 elm_genlist_item_expanded_set(it, EINA_TRUE);
1147 }
1148
1149 static void
_on_list_contract_req(void * data EINA_UNUSED,const Efl_Event * event)1150 _on_list_contract_req(void *data EINA_UNUSED, const Efl_Event *event)
1151 {
1152 Elm_Object_Item *it = event->info;
1153
1154 elm_genlist_item_expanded_set(it, EINA_FALSE);
1155 }
1156
1157 static void
_on_item_activated(void * data,const Efl_Event * event)1158 _on_item_activated(void *data, const Efl_Event *event)
1159 {
1160 //This event_info could be a list or gengrid item
1161 Elm_Object_Item *it = event->info;
1162 const Elm_Fileselector_Item_Data *it_data;
1163
1164 ELM_FILESELECTOR_DATA_GET(data, sd);
1165
1166 it_data = elm_object_item_data_get(it);
1167 if (!it_data) return;
1168
1169 if (!it_data->is_dir)
1170 {
1171 _model_event_call(data, ELM_FILESELECTOR_EVENT_ACTIVATED, ELM_FILESELECTOR_EVENT_ACTIVATED->name, it_data->model, it_data->path);
1172 return;
1173 }
1174
1175 if (!sd->double_tap_navigation) return;
1176
1177 // Set the Efl.Io.Model parent to be the fileselector to prevent death when populate
1178 efl_parent_set(efl_ui_view_model_get(it_data->model), data);
1179 _populate(data, it_data->model, NULL, NULL);
1180 }
1181
1182 static void
_clear_selections(Elm_Fileselector_Data * sd,Elm_Object_Item * last_selected)1183 _clear_selections(Elm_Fileselector_Data *sd, Elm_Object_Item *last_selected)
1184 {
1185 Eina_List *items;
1186 Elm_Object_Item *sel;
1187
1188 if (sd->mode == ELM_FILESELECTOR_LIST)
1189 {
1190 items = eina_list_clone(elm_genlist_selected_items_get(sd->files_view));
1191
1192 EINA_LIST_FREE(items, sel)
1193 {
1194 if (sel == last_selected) continue;
1195 elm_genlist_item_selected_set(sel, EINA_FALSE);
1196 }
1197 }
1198 else if (sd->mode == ELM_FILESELECTOR_GRID)
1199 {
1200 items = eina_list_clone(elm_gengrid_selected_items_get(sd->files_view));
1201
1202 EINA_LIST_FREE(items, sel)
1203 {
1204 if (sel == last_selected) continue;
1205 elm_gengrid_item_selected_set(sel, EINA_FALSE);
1206 }
1207 }
1208 }
1209
1210 static void
_on_item_selected(void * data,Evas_Object * obj EINA_UNUSED,void * event_info)1211 _on_item_selected(void *data, Evas_Object *obj EINA_UNUSED, void *event_info)
1212 {
1213 //This event_info could be a list or gengrid item
1214 Elm_Object_Item *it = event_info;
1215 Elm_Fileselector_Item_Data *it_data = NULL;
1216
1217 ELM_FILESELECTOR_DATA_GET(data, sd);
1218
1219 it_data = elm_object_item_data_get(it);
1220 if (!it_data) return;
1221
1222 /* We need to send callback when:
1223 * - path is dir and mode is ONLY FOLDER
1224 * - path is file and mode is NOT ONLY FOLDER */
1225 if (it_data->is_dir == sd->only_folder)
1226 {
1227 if (sd->multi)
1228 {
1229 Eina_List *li;
1230 Elm_Object_Item *it2;
1231 Eina_Strbuf *buf;
1232
1233 if (sd->dir_selected)
1234 {
1235 _clear_selections(sd, it);
1236 sd->dir_selected = EINA_FALSE;
1237 }
1238
1239 buf = eina_strbuf_new();
1240 EINA_LIST_FOREACH(sd->multi_selection, li, it2)
1241 {
1242 Elm_Fileselector_Item_Data *it2_data = elm_object_item_data_get(it2);
1243 eina_strbuf_append(buf, it2_data->filename);
1244 eina_strbuf_append_length(buf, ", ", 2);
1245 }
1246
1247 sd->multi_selection = eina_list_append(sd->multi_selection, it);
1248 eina_strbuf_append(buf, it_data->filename);
1249
1250 elm_object_text_set(sd->name_entry, eina_strbuf_string_get(buf));
1251 eina_strbuf_free(buf);
1252 }
1253 else
1254 elm_object_text_set(sd->name_entry, it_data->filename);
1255
1256 _model_event_call(data, EFL_UI_EVENT_ITEM_SELECTED, "selected", it_data->model, it_data->path);
1257 }
1258 else if (sd->multi && it_data->is_dir && sd->double_tap_navigation)
1259 {
1260 _clear_selections(sd, it);
1261 sd->dir_selected = EINA_TRUE;
1262 }
1263
1264 /* We need to populate, if path is directory and:
1265 * - mode is GRID;
1266 * - mode is LIST and 'not expand mode';
1267 * in other cases update anchors. */
1268
1269 if (sd->expand && sd->mode == ELM_FILESELECTOR_LIST)
1270 {
1271 if (!it_data->is_dir)
1272 {
1273 _elm_fileselector_replace_model(data, sd, it_data->parent_model, it_data->parent_path);
1274 _anchors_do(data, it_data->parent_path);
1275 return;
1276 }
1277 if (sd->only_folder)
1278 {
1279 _elm_fileselector_replace_model(data, sd, it_data->parent_model, it_data->parent_path);
1280 _anchors_do(data, it_data->parent_path);
1281 }
1282 else
1283 {
1284 _elm_fileselector_replace_model(data, sd, it_data->model, it_data->path);
1285 _anchors_do(data, it_data->path);
1286 }
1287 // Clear name entry not in case of save mode.
1288 if (elm_object_disabled_get(sd->name_entry))
1289 elm_object_text_set(sd->name_entry, "");
1290 return;
1291 }
1292
1293 if (!it_data->is_dir) return;
1294
1295 if (sd->double_tap_navigation) return;
1296
1297 _populate(data, it_data->model, NULL, NULL);
1298 }
1299
1300 static void
_on_item_unselected(void * data,Evas_Object * obj EINA_UNUSED,void * event_info)1301 _on_item_unselected(void *data, Evas_Object *obj EINA_UNUSED, void *event_info)
1302 {
1303 Eina_List *li, *l;
1304 const Elm_Fileselector_Item_Data *it_data;
1305 Eina_Strbuf *buf;
1306 Elm_Object_Item *it = event_info;
1307 Elm_Object_Item *it2 = NULL;
1308 Eina_Bool first = EINA_TRUE;
1309
1310 ELM_FILESELECTOR_DATA_GET(data, sd);
1311
1312 if (!sd->multi) return;
1313
1314 it_data = elm_object_item_data_get(it);
1315 if (!it_data) return;
1316
1317 buf = eina_strbuf_new();
1318 EINA_LIST_FOREACH_SAFE(sd->multi_selection, li, l, it2)
1319 {
1320 if (it2 == it)
1321 {
1322 sd->multi_selection = eina_list_remove_list(sd->multi_selection, li);
1323 }
1324 else
1325 {
1326 Elm_Fileselector_Item_Data *it2_data = elm_object_item_data_get(it2);
1327 if (!it2_data)
1328 continue;
1329 if (!first)
1330 eina_strbuf_append_length(buf, ", ", 2);
1331 else
1332 first = EINA_FALSE;
1333
1334 eina_strbuf_append(buf, it2_data->path);
1335 }
1336 }
1337
1338 elm_object_text_set(sd->name_entry, eina_strbuf_string_get(buf));
1339 eina_strbuf_free(buf);
1340 }
1341
1342 static void
_on_dir_up(void * data,Evas_Object * obj EINA_UNUSED,void * event_info EINA_UNUSED)1343 _on_dir_up(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
1344 {
1345 Evas_Object *fs = data;
1346 Efl_Model *parent = NULL;
1347
1348 ELM_FILESELECTOR_DATA_GET(fs, sd);
1349
1350 parent = efl_parent_get(sd->model);
1351 if (!parent) return;
1352
1353 if (!efl_isa(parent, EFL_IO_MODEL_CLASS))
1354 {
1355 const char *path = _io_path_get(sd->model);
1356 char dir[PATH_MAX] = "";
1357 char *r;
1358
1359 eina_strlcpy(dir, path, sizeof (dir));
1360 r = dirname(dir);
1361
1362 // In case we have reached '/'
1363 if (!strcmp(r, path)) return ;
1364
1365 elm_fileselector_path_set(fs, r);
1366 }
1367 else
1368 {
1369 _populate(fs, parent, NULL, NULL);
1370 }
1371 }
1372
1373 static void
_home(void * data,Evas_Object * obj EINA_UNUSED,void * event_info EINA_UNUSED)1374 _home(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
1375 {
1376 Evas_Object *fs = data;
1377
1378 // FIXME: maybe use vpath
1379 elm_fileselector_path_set(fs, eina_environment_home_get());
1380 }
1381
1382 static void
_current_filter_changed(void * data,Evas_Object * obj,void * event_info EINA_UNUSED)1383 _current_filter_changed(void *data,
1384 Evas_Object *obj,
1385 void *event_info EINA_UNUSED)
1386 {
1387 Elm_Fileselector_Filter *filter = data;
1388
1389 if (filter->sd->current_filter == filter) return;
1390
1391 elm_object_text_set(obj, filter->filter_name);
1392 filter->sd->current_filter = filter;
1393
1394 _populate(filter->sd->obj, filter->sd->model, NULL, NULL);
1395 }
1396
1397 static void
_ok(void * data,Evas_Object * obj EINA_UNUSED,void * event_info EINA_UNUSED)1398 _ok(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
1399 {
1400 const char *name;
1401 const char *selection = NULL;
1402 Evas_Object *fs = data;
1403 ELM_FILESELECTOR_DATA_GET(fs, sd);
1404
1405 if (!sd->model || !sd->path)
1406 {
1407 _model_event_call(fs, ELM_FILESELECTOR_EVENT_DONE, ELM_FILESELECTOR_EVENT_DONE->name, NULL, NULL);
1408 return;
1409 }
1410
1411 name = elm_object_text_get(sd->name_entry);
1412 if (name && name[0] != '\0')
1413 {
1414 Efl_Model *selected_model = NULL;
1415 int len = eina_stringshare_strlen(sd->path);
1416 if (sd->path[len - 1] == '/')
1417 selection = eina_stringshare_printf("%s%s", sd->path, name);
1418 else
1419 selection = eina_stringshare_printf("%s/%s", sd->path, name);
1420
1421 selected_model = efl_add_ref(efl_class_get(efl_ui_view_model_get(sd->model)), fs,
1422 efl_event_callback_array_add(efl_added, noref_death(), NULL),
1423 efl_io_model_path_set(efl_added, selection));
1424
1425 _model_event_call(fs, ELM_FILESELECTOR_EVENT_DONE, ELM_FILESELECTOR_EVENT_DONE->name, selected_model, selection);
1426
1427 efl_unref(selected_model);
1428 eina_stringshare_del(selection);
1429 }
1430 else
1431 {
1432 Elm_Fileselector_Item_Data *it_data = _selected_item_data_get(sd);
1433 if (it_data)
1434 {
1435 _model_event_call(fs, ELM_FILESELECTOR_EVENT_DONE, ELM_FILESELECTOR_EVENT_DONE->name, it_data->model, it_data->path);
1436 }
1437 else
1438 {
1439 _model_event_call(fs, ELM_FILESELECTOR_EVENT_DONE, ELM_FILESELECTOR_EVENT_DONE->name, sd->model, sd->path);
1440 }
1441 }
1442 }
1443
1444 static void
_canc(void * data,Evas_Object * obj EINA_UNUSED,void * event_info EINA_UNUSED)1445 _canc(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
1446 {
1447 Evas_Object *fs = data;
1448
1449 _model_event_call(fs, ELM_FILESELECTOR_EVENT_DONE, ELM_FILESELECTOR_EVENT_DONE->name, NULL, NULL);
1450 }
1451
1452 static void
_on_text_activated(void * data,const Efl_Event * event)1453 _on_text_activated(void *data, const Efl_Event *event)
1454 {
1455 Evas_Object *fs = data;
1456 const char *path;
1457 Efl_Model *model = NULL, *parent;
1458 Eina_Bool dir = EINA_FALSE;
1459
1460 ELM_FILESELECTOR_DATA_GET(fs, sd);
1461
1462 if (!sd->model) return;
1463
1464 path = elm_widget_part_text_get(event->object, NULL);
1465 if (!ecore_file_exists(path))
1466 {
1467 _model_event_call(fs, ELM_FILESELECTOR_EVENT_SELECTED_INVALID,
1468 ELM_FILESELECTOR_EVENT_SELECTED_INVALID->name, NULL, path);
1469
1470 elm_widget_part_text_set(event->object, NULL, _io_path_get(sd->model));
1471 goto end;
1472 }
1473
1474 if (!ecore_file_is_dir(path))
1475 {
1476 model = efl_add_ref(efl_class_get(efl_ui_view_model_get(sd->model)), fs,
1477 efl_io_model_path_set(efl_added, path),
1478 efl_event_callback_array_add(efl_added, noref_death(), NULL));
1479
1480 path = eina_slstr_steal_new(ecore_file_dir_get(path));
1481 }
1482 else
1483 {
1484 dir = EINA_TRUE;
1485 }
1486
1487 parent = efl_add_ref(efl_class_get(efl_ui_view_model_get(sd->model)), fs,
1488 efl_io_model_path_set(efl_added, path),
1489 efl_event_callback_array_add(efl_added, noref_death(), NULL));
1490 if (!parent) goto end;
1491
1492 _populate(fs, parent, NULL, model);
1493
1494 if (sd->only_folder && dir)
1495 _model_event_call(fs, EFL_UI_EVENT_ITEM_SELECTED, "selected", parent, path);
1496
1497 end:
1498 elm_object_focus_set(event->object, EINA_FALSE);
1499 }
1500
1501 static Eina_Bool
_anchors_undo(void * data)1502 _anchors_undo(void *data)
1503 {
1504 ELM_FILESELECTOR_DATA_GET(data, sd);
1505
1506 elm_entry_entry_set(sd->path_entry, sd->path);
1507 elm_entry_cursor_pos_set(sd->path_entry, eina_stringshare_strlen(sd->path));
1508
1509 sd->path_entry_idler = NULL;
1510
1511 return ECORE_CALLBACK_CANCEL;
1512 }
1513
1514 static void
_on_text_focus_changed(void * data,const Efl_Event * event)1515 _on_text_focus_changed(void *data, const Efl_Event *event)
1516 {
1517 ELM_FILESELECTOR_DATA_GET(data, sd);
1518
1519 if (efl_ui_focus_object_focus_get(event->object))
1520 {
1521 if (!sd->path_entry_idler)
1522 sd->path_entry_idler = ecore_idler_add(_anchors_undo, data);
1523 }
1524 else
1525 {
1526 _anchors_do(data, sd->path);
1527 }
1528 }
1529
1530 static void
_anchor_clicked(void * data,const Efl_Event * event)1531 _anchor_clicked(void *data, const Efl_Event *event)
1532 {
1533 Elm_Entry_Anchor_Info *info = event->info;
1534 Evas_Object *fs = data;
1535 Efl_Model *model = NULL;
1536
1537 ELM_FILESELECTOR_DATA_GET(fs, sd);
1538
1539 if (!sd->model) return;
1540
1541 model = efl_add_ref(efl_class_get(efl_ui_view_model_get(sd->model)), fs,
1542 efl_event_callback_array_add(efl_added, noref_death(), NULL),
1543 efl_io_model_path_set(efl_added, info->name));
1544 if (!model) return;
1545
1546 _populate(fs, model, NULL, NULL);
1547 efl_unref(model);
1548 /* After anchor was clicked, entry will be focused, and will be editable.
1549 * It's wrong. So remove focus. */
1550 elm_object_focus_set(event->object, EINA_FALSE);
1551
1552 if (sd->path_entry_idler) {
1553 ecore_idler_del(sd->path_entry_idler);
1554 sd->path_entry_idler = NULL;
1555 }
1556 }
1557
1558 static void
_files_key_down(void * data,const Efl_Event * event)1559 _files_key_down(void *data, const Efl_Event *event)
1560 {
1561 Efl_Input_Key *ev = event->info;
1562 Evas_Object *par, *searchbar;
1563 const char *string, *key;
1564
1565 par = data;
1566 searchbar = evas_object_data_get(par, "search");
1567
1568 if (!searchbar) return;
1569
1570 key = efl_input_key_sym_get(ev);
1571 string = efl_input_key_string_get(ev);
1572 if (string && *(string) && (isalpha(*string) || isdigit(*string)))
1573 {
1574
1575 elm_entry_entry_append(searchbar, string);
1576 efl_input_processed_set(ev, EINA_TRUE);
1577 }
1578 else if (key && *(key) && !strcmp(key, "BackSpace"))
1579 {
1580 char buf[PATH_MAX];
1581 const char *en;
1582 en = elm_entry_entry_get(searchbar);
1583 if (en && strlen(en) > 0)
1584 {
1585 memmove(buf, en, strlen(en) -1);
1586 buf[strlen(en) -1] = '\0';
1587 elm_entry_entry_set(searchbar, buf);
1588 efl_input_processed_set(ev, EINA_TRUE);
1589 }
1590 }
1591 }
1592
1593 static Evas_Object *
_files_list_add(Evas_Object * obj)1594 _files_list_add(Evas_Object *obj)
1595 {
1596 Evas_Object *li;
1597
1598 li = elm_genlist_add(obj);
1599 evas_object_data_set(li, "parent", obj);
1600 efl_ui_mirrored_automatic_set(li, EINA_FALSE);
1601
1602 evas_object_smart_callback_add(li, "selected", _on_item_selected, obj);
1603 evas_object_smart_callback_add(li, "unselected", _on_item_unselected, obj);
1604 efl_event_callback_add
1605 (li, ELM_GENLIST_EVENT_ACTIVATED, _on_item_activated, obj);
1606 efl_event_callback_add
1607 (li, ELM_GENLIST_EVENT_EXPAND_REQUEST, _on_list_expand_req, obj);
1608 efl_event_callback_add
1609 (li, ELM_GENLIST_EVENT_CONTRACT_REQUEST, _on_list_contract_req, obj);
1610 efl_event_callback_add
1611 (li, ELM_GENLIST_EVENT_EXPANDED, _on_list_expanded, obj);
1612 efl_event_callback_add
1613 (li, ELM_GENLIST_EVENT_CONTRACTED, _on_list_contracted, obj);
1614 efl_event_callback_add
1615 (li, EFL_EVENT_KEY_DOWN, _files_key_down, obj);
1616
1617 return li;
1618 }
1619
1620 static Evas_Object *
_files_grid_add(Evas_Object * obj)1621 _files_grid_add(Evas_Object *obj)
1622 {
1623 Evas_Object *grid;
1624
1625 ELM_FILESELECTOR_DATA_GET(obj, sd);
1626
1627 grid = elm_gengrid_add(obj);
1628 evas_object_data_set(grid, "parent", obj);
1629 efl_ui_mirrored_automatic_set(grid, EINA_FALSE);
1630 evas_object_size_hint_align_set(grid, EVAS_HINT_FILL, EVAS_HINT_FILL);
1631 evas_object_size_hint_weight_set(grid, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1632
1633 elm_gengrid_item_size_set(grid, sd->thumbnail_size.w, sd->thumbnail_size.h);
1634
1635 elm_gengrid_align_set(grid, 0.0, 0.0);
1636
1637 evas_object_smart_callback_add(grid, "selected", _on_item_selected, obj);
1638 evas_object_smart_callback_add(grid, "unselected", _on_item_unselected, obj);
1639 efl_event_callback_add
1640 (grid, ELM_GENGRID_EVENT_ACTIVATED, _on_item_activated, obj);
1641 efl_event_callback_add
1642 (grid, EFL_EVENT_KEY_DOWN, _files_key_down, obj);
1643
1644 return grid;
1645 }
1646
1647 static Eina_Value
_resource_created_then(Eo * model EINA_UNUSED,void * data,const Eina_Value v)1648 _resource_created_then(Eo *model EINA_UNUSED, void *data, const Eina_Value v)
1649 {
1650 Evas_Object *fs = data;
1651 Efl_Model *child = NULL;
1652 unsigned int len, i;
1653
1654 ELM_FILESELECTOR_DATA_GET(fs, sd);
1655
1656 EINA_VALUE_ARRAY_FOREACH(&v, len, i, child)
1657 _process_model(sd, child, NULL); //this function will always just work for the root model of the fileselector
1658
1659 return v;
1660 }
1661
1662 static void
_resource_created(void * data,const Efl_Event * event)1663 _resource_created(void *data, const Efl_Event *event)
1664 {
1665 Elm_Fileselector *fs = data;
1666 Efl_Model_Children_Event* evt = event->info;
1667 Eina_Future *f;
1668
1669 ELM_FILESELECTOR_DATA_GET(fs, sd);
1670
1671 if (!sd || !sd->monitoring || sd->model != event->object)
1672 return;
1673
1674 f = efl_model_children_slice_get(sd->model, evt->index, 1);
1675 f = efl_future_then(fs, f);
1676 f = efl_future_then(sd->model, f,
1677 .success = _resource_created_then,
1678 .data = fs);
1679 }
1680
1681 static void
_resource_deleted(void * data,const Efl_Event * event)1682 _resource_deleted(void *data, const Efl_Event *event)
1683 {
1684 Evas_Object *obj = data;
1685 Efl_Model_Children_Event* evt = event->info;
1686 Elm_Object_Item *it = NULL;
1687 Eina_Bool selected = EINA_FALSE;
1688
1689 ELM_FILESELECTOR_DATA_GET(obj, sd);
1690
1691 if (!sd || !sd->monitoring || sd->model != event->object)
1692 return;
1693
1694 if (!evt->child) return ;
1695
1696 it = efl_key_data_get(evt->child, ".item.data");
1697 if (!it) return ;
1698
1699 selected = elm_genlist_item_selected_get(it);
1700
1701 if (selected)
1702 {
1703 if (sd->multi)
1704 {
1705 Eina_List *li, *l;
1706 Elm_Object_Item *item;
1707 Eina_Strbuf *buf;
1708 Eina_Bool first = EINA_TRUE;
1709
1710 buf = eina_strbuf_new();
1711 EINA_LIST_FOREACH_SAFE(sd->multi_selection, li, l, item)
1712 {
1713 if (item == it)
1714 {
1715 sd->multi_selection = eina_list_remove_list(sd->multi_selection, li);
1716 }
1717 else
1718 {
1719 Elm_Fileselector_Item_Data *it_data = elm_object_item_data_get(item);
1720
1721 if (!first)
1722 eina_strbuf_append_length(buf, ", ", 2);
1723 else
1724 first = EINA_FALSE;
1725
1726 eina_strbuf_append(buf, it_data->filename);
1727 }
1728 }
1729
1730 elm_object_text_set(sd->name_entry, eina_strbuf_string_get(buf));
1731 eina_strbuf_free(buf);
1732 }
1733 else
1734 elm_object_text_set(sd->name_entry, "");
1735 }
1736
1737 if (it) efl_del(it);
1738
1739 return;
1740 }
1741
1742 static void
_preedit_cb(void * data,const Efl_Event * event)1743 _preedit_cb(void *data, const Efl_Event *event)
1744 {
1745 ELM_FILESELECTOR_DATA_GET(data, sd);
1746
1747 sd->search_string = elm_entry_entry_get(event->object);
1748
1749 if (sd->search_string && sd->model)
1750 _populate(data, sd->model, NULL, NULL);
1751 }
1752
1753 EOLIAN static void
_elm_fileselector_efl_canvas_group_group_add(Eo * obj,Elm_Fileselector_Data * priv)1754 _elm_fileselector_efl_canvas_group_group_add(Eo *obj, Elm_Fileselector_Data *priv)
1755 {
1756 Evas_Object *ic, *bt, *en, *pb;
1757 const char *data;
1758 char buf[1024];
1759
1760 efl_canvas_group_add(efl_super(obj, MY_CLASS));
1761 elm_widget_can_focus_set(obj, EINA_FALSE);
1762
1763 priv->expand = !!_elm_config->fileselector_expand_enable;
1764 priv->double_tap_navigation = !!_elm_config->fileselector_double_tap_navigation_enable;
1765
1766 if (!elm_layout_theme_set
1767 (obj, "fileselector", "base", elm_widget_style_get(obj)))
1768 CRI("Failed to set layout!");
1769
1770 ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd);
1771
1772 data = edje_object_data_get
1773 (wd->resize_obj, "path_separator");
1774 if (data) priv->path_separator = data;
1775 else priv->path_separator = "/";
1776
1777 snprintf(buf, sizeof(buf), "fileselector/%s", elm_widget_style_get(obj));
1778
1779 // up btn
1780 ic = elm_icon_add(obj);
1781 elm_icon_standard_set(ic, "go-up");
1782 bt = elm_button_add(obj);
1783 efl_ui_mirrored_automatic_set(bt, EINA_FALSE);
1784 elm_object_part_content_set(bt, "icon", ic);
1785 elm_object_domain_translatable_text_set(bt, PACKAGE, N_("Up"));
1786
1787 evas_object_smart_callback_add(bt, "clicked", _on_dir_up, obj);
1788
1789 priv->up_button = bt;
1790 elm_object_style_set(priv->up_button, buf);
1791 elm_object_part_content_set(obj, "elm.swallow.up", priv->up_button);
1792
1793 // home btn
1794 ic = elm_icon_add(obj);
1795 elm_icon_standard_set(ic, "go-home");
1796 bt = elm_button_add(obj);
1797 efl_ui_mirrored_automatic_set(bt, EINA_FALSE);
1798 elm_object_part_content_set(bt, "icon", ic);
1799 elm_object_domain_translatable_text_set(bt, PACKAGE, N_("Home"));
1800 evas_object_smart_callback_add(bt, "clicked", _home, obj);
1801
1802 priv->home_button = bt;
1803 elm_object_style_set(priv->home_button, buf);
1804 elm_object_part_content_set(obj, "elm.swallow.home", priv->home_button);
1805
1806 // search entry
1807 ic = elm_icon_add(obj);
1808 elm_icon_standard_set(ic, "edit-find");
1809 evas_object_size_hint_aspect_set(ic, EVAS_ASPECT_CONTROL_VERTICAL, 1, 1);
1810 en = elm_entry_add(obj);
1811 elm_entry_scrollable_set(en, EINA_TRUE);
1812 efl_ui_mirrored_automatic_set(en, EINA_FALSE);
1813 elm_entry_editable_set(en, EINA_TRUE);
1814 elm_entry_single_line_set(en, EINA_TRUE);
1815 elm_entry_line_wrap_set(en, ELM_WRAP_CHAR);
1816 elm_object_domain_translatable_part_text_set(en, "guide",
1817 PACKAGE, N_("Search"));
1818 elm_object_part_content_set(en, "icon", ic);
1819 elm_entry_icon_visible_set(en, EINA_TRUE);
1820 efl_event_callback_add
1821 (en, ELM_ENTRY_EVENT_CHANGED, _preedit_cb, obj);
1822 evas_object_data_set(obj, "search", en);
1823
1824 priv->search_entry = en;
1825 elm_object_style_set(priv->search_entry, buf);
1826 elm_object_part_content_set(obj, "elm.swallow.search", priv->search_entry);
1827
1828 // spinner
1829 pb = elm_progressbar_add(obj);
1830 priv->spinner = pb;
1831 elm_progressbar_pulse_set(priv->spinner, EINA_TRUE);
1832 elm_object_style_set(priv->spinner, "wheel");
1833 elm_object_part_content_set(obj, "elm.swallow.spinner", priv->spinner);
1834
1835 priv->thumbnail_size.w = ITEM_SIZE_DEFAULT;
1836 priv->thumbnail_size.h = ITEM_SIZE_DEFAULT;
1837
1838 priv->sort_type = ELM_FILESELECTOR_SORT_BY_FILENAME_ASC;
1839 priv->sort_method = _filename_cmp;
1840
1841 // path entry
1842 en = elm_entry_add(obj);
1843 elm_entry_scrollable_set(en, EINA_TRUE);
1844 efl_ui_mirrored_automatic_set(en, EINA_FALSE);
1845 elm_entry_single_line_set(en, EINA_TRUE);
1846 elm_entry_line_wrap_set(en, ELM_WRAP_CHAR);
1847
1848 efl_event_callback_add
1849 (en, ELM_ENTRY_EVENT_ANCHOR_CLICKED, _anchor_clicked, obj);
1850 efl_event_callback_add
1851 (en, EFL_UI_FOCUS_OBJECT_EVENT_FOCUS_CHANGED, _on_text_focus_changed, obj);
1852 efl_event_callback_add
1853 (en, ELM_ENTRY_EVENT_ACTIVATED, _on_text_activated, obj);
1854
1855 priv->path_entry = en;
1856 elm_object_style_set(priv->path_entry, buf);
1857 elm_object_part_content_set(obj, "elm.swallow.path", priv->path_entry);
1858
1859 // name entry
1860 en = elm_entry_add(obj);
1861 elm_entry_scrollable_set(en, EINA_TRUE);
1862 efl_ui_mirrored_automatic_set(en, EINA_FALSE);
1863 elm_entry_editable_set(en, EINA_TRUE);
1864 elm_entry_single_line_set(en, EINA_TRUE);
1865 elm_entry_line_wrap_set(en, ELM_WRAP_CHAR);
1866
1867 priv->name_entry = en;
1868 elm_object_style_set(priv->name_entry, buf);
1869 elm_object_part_content_set(obj, "elm.swallow.filename", priv->name_entry);
1870
1871 // ok cancel button
1872 elm_fileselector_buttons_ok_cancel_set(obj, EINA_TRUE);
1873 elm_fileselector_is_save_set(obj, EINA_FALSE);
1874
1875 // files_view
1876 priv->files_view = _files_list_add(obj);
1877 elm_object_part_content_set(obj, "elm.swallow.files", priv->files_view);
1878
1879 elm_layout_sizing_eval(obj);
1880
1881 _focus_chain_update(obj, priv);
1882 }
1883
1884 EOLIAN static void
_elm_fileselector_efl_canvas_group_group_del(Eo * obj,Elm_Fileselector_Data * sd)1885 _elm_fileselector_efl_canvas_group_group_del(Eo *obj, Elm_Fileselector_Data *sd)
1886 {
1887 Elm_Fileselector_Filter *filter;
1888
1889 if (sd->current_populate_lreq)
1890 sd->current_populate_lreq->valid = EINA_FALSE;
1891 sd->current_populate_lreq = NULL;
1892
1893 if (sd->model)
1894 _monitoring_stop(obj, sd, sd->model);
1895
1896 EINA_LIST_FREE(sd->filter_list, filter)
1897 {
1898 eina_stringshare_del(filter->filter_name);
1899
1900 if (filter->filter_type == ELM_FILESELECTOR_MIME_FILTER)
1901 {
1902 free(filter->filter.mime_types[0]);
1903 free(filter->filter.mime_types);
1904 }
1905 else
1906 free(filter->filter.custom);
1907
1908 free(filter);
1909 }
1910
1911 sd->multi_selection = eina_list_free(sd->multi_selection);
1912 sd->multi_selection_tmp = eina_list_free(sd->multi_selection_tmp);
1913 sd->files_view = NULL;
1914 _elm_fileselector_smart_del_do(obj, sd);
1915 }
1916
1917 EAPI Evas_Object *
elm_fileselector_add(Evas_Object * parent)1918 elm_fileselector_add(Evas_Object *parent)
1919 {
1920 EINA_SAFETY_ON_NULL_RETURN_VAL(parent, NULL);
1921 return elm_legacy_add(MY_CLASS, parent);
1922 }
1923
1924 EOLIAN static Eo *
_elm_fileselector_efl_object_constructor(Eo * obj,Elm_Fileselector_Data * sd)1925 _elm_fileselector_efl_object_constructor(Eo *obj, Elm_Fileselector_Data *sd)
1926 {
1927 obj = efl_constructor(efl_super(obj, MY_CLASS));
1928 legacy_child_focus_handle(obj);
1929 sd->obj = obj;
1930 efl_canvas_object_type_set(obj, MY_CLASS_NAME_LEGACY);
1931 evas_object_smart_callbacks_descriptions_set(obj, _smart_callbacks);
1932 efl_access_object_role_set(obj, EFL_ACCESS_ROLE_FILE_CHOOSER);
1933
1934 return obj;
1935 }
1936
1937 static Eina_Bool
_from_efl_event_call(Elm_Fileselector * fs,const Efl_Event_Description * evt_desc,Efl_Model * model)1938 _from_efl_event_call(Elm_Fileselector *fs, const Efl_Event_Description *evt_desc, Efl_Model *model)
1939 {
1940 Eina_Value *fetch;
1941 const char *evt;
1942 char *path;
1943
1944 // Call legacy smart callback with path
1945 fetch = efl_model_property_get(model, "path");
1946 path = eina_value_to_string(fetch);
1947
1948 evt = evt_desc == EFL_UI_EVENT_ITEM_SELECTED ? "selected" : evt_desc->name;
1949 _event_to_legacy_call(fs, evt, path);
1950
1951 // Call Eo event with model
1952 return efl_event_callback_call(fs, evt_desc, model);
1953 }
1954
1955 static Eina_Bool
_from_legacy_event_call(Elm_Fileselector * fs,Elm_Fileselector_Data * sd,const Efl_Event_Description * legacy_desc,const Efl_Event_Description * evt_desc,const char * path)1956 _from_legacy_event_call(Elm_Fileselector *fs, Elm_Fileselector_Data *sd, const Efl_Event_Description *legacy_desc, const Efl_Event_Description *evt_desc, const char *path)
1957 {
1958 const Efl_Class *model_cls = NULL;
1959 if (!sd->model)
1960 model_cls = EFL_IO_MODEL_CLASS;
1961 else
1962 model_cls = efl_class_get(efl_ui_view_model_get(sd->model));
1963
1964 Efl_Model *model = efl_add_ref(model_cls, fs,
1965 efl_event_callback_array_add(efl_added, noref_death(), NULL),
1966 efl_io_model_path_set(efl_added, path));
1967
1968 // Call Eo event with model
1969 efl_event_callback_call(fs, evt_desc, model);
1970
1971 efl_unref(model);
1972
1973 // Call legacy smart callback with path
1974 return efl_event_callback_call(fs, legacy_desc, (void *)path);
1975 }
1976
1977 EOLIAN static Eina_Bool
_elm_fileselector_efl_object_event_callback_legacy_call(Eo * obj,Elm_Fileselector_Data * sd,const Efl_Event_Description * desc,void * event_info)1978 _elm_fileselector_efl_object_event_callback_legacy_call(Eo *obj, Elm_Fileselector_Data *sd,
1979 const Efl_Event_Description *desc, void *event_info)
1980 {
1981 if (desc->legacy_is)
1982 {
1983 const Efl_Event_Description *evt_desc = NULL;
1984 if (strcmp(desc->name, "selected") == 0)
1985 evt_desc = EFL_UI_EVENT_ITEM_SELECTED;
1986 else if (strcmp(desc->name, "activated") == 0)
1987 evt_desc = ELM_FILESELECTOR_EVENT_ACTIVATED;
1988 else if (strcmp(desc->name, "directory,open") == 0)
1989 evt_desc = ELM_FILESELECTOR_EVENT_DIRECTORY_OPEN;
1990 else if (strcmp(desc->name, "done") == 0)
1991 evt_desc = ELM_FILESELECTOR_EVENT_DONE;
1992 else if (strcmp(desc->name, "selected,invalid") == 0)
1993 evt_desc = ELM_FILESELECTOR_EVENT_SELECTED_INVALID;
1994 else
1995 return efl_event_callback_legacy_call(efl_super(obj, MY_CLASS), desc, event_info);
1996
1997 return _from_legacy_event_call(obj, sd, desc, evt_desc, event_info);
1998 }
1999
2000 if (desc == EFL_UI_EVENT_ITEM_SELECTED ||
2001 desc == ELM_FILESELECTOR_EVENT_ACTIVATED ||
2002 desc == ELM_FILESELECTOR_EVENT_DIRECTORY_OPEN ||
2003 desc == ELM_FILESELECTOR_EVENT_DONE ||
2004 desc == ELM_FILESELECTOR_EVENT_SELECTED_INVALID)
2005 {
2006 return _from_efl_event_call(obj, desc, event_info);
2007 }
2008
2009 return efl_event_callback_legacy_call(efl_super(obj, MY_CLASS), desc, event_info);
2010 }
2011
2012 EAPI void
elm_fileselector_is_save_set(Evas_Object * obj,Eina_Bool is_save)2013 elm_fileselector_is_save_set(Evas_Object *obj,
2014 Eina_Bool is_save)
2015 {
2016 ELM_FILESELECTOR_INTERFACE_CHECK(obj);
2017 elm_interface_fileselector_is_save_set(obj, is_save);
2018 }
2019
2020 EOLIAN static void
_elm_fileselector_elm_interface_fileselector_is_save_set(Eo * obj,Elm_Fileselector_Data * sd,Eina_Bool is_save)2021 _elm_fileselector_elm_interface_fileselector_is_save_set(Eo *obj, Elm_Fileselector_Data *sd, Eina_Bool is_save)
2022 {
2023 elm_object_disabled_set(sd->name_entry, !is_save);
2024
2025 if (is_save) elm_layout_signal_emit(obj, "elm,state,save,on", "elm");
2026 else elm_layout_signal_emit(obj, "elm,state,save,off", "elm");
2027
2028 _focus_chain_update(obj, sd);
2029 }
2030
2031 EAPI Eina_Bool
elm_fileselector_is_save_get(const Evas_Object * obj)2032 elm_fileselector_is_save_get(const Evas_Object *obj)
2033 {
2034 ELM_FILESELECTOR_INTERFACE_CHECK(obj, EINA_FALSE);
2035 return elm_interface_fileselector_is_save_get((Eo *) obj);
2036 }
2037
2038 EOLIAN static Eina_Bool
_elm_fileselector_elm_interface_fileselector_is_save_get(const Eo * obj EINA_UNUSED,Elm_Fileselector_Data * sd)2039 _elm_fileselector_elm_interface_fileselector_is_save_get(const Eo *obj EINA_UNUSED, Elm_Fileselector_Data *sd)
2040 {
2041 return !elm_object_disabled_get(sd->name_entry);
2042 }
2043
2044 EAPI void
elm_fileselector_folder_only_set(Evas_Object * obj,Eina_Bool only)2045 elm_fileselector_folder_only_set(Evas_Object *obj,
2046 Eina_Bool only)
2047 {
2048 ELM_FILESELECTOR_INTERFACE_CHECK(obj);
2049 elm_interface_fileselector_folder_only_set(obj, only);
2050 }
2051
2052 EOLIAN static void
_elm_fileselector_elm_interface_fileselector_folder_only_set(Eo * obj,Elm_Fileselector_Data * sd,Eina_Bool only)2053 _elm_fileselector_elm_interface_fileselector_folder_only_set(Eo *obj, Elm_Fileselector_Data *sd, Eina_Bool only)
2054 {
2055 if (sd->only_folder == only) return;
2056
2057 sd->only_folder = !!only;
2058 if (sd->model)
2059 {
2060 _populate(obj, sd->model, NULL, NULL);
2061 }
2062 }
2063
2064 EAPI Eina_Bool
elm_fileselector_folder_only_get(const Evas_Object * obj)2065 elm_fileselector_folder_only_get(const Evas_Object *obj)
2066 {
2067 ELM_FILESELECTOR_INTERFACE_CHECK(obj, EINA_FALSE);
2068 return elm_interface_fileselector_folder_only_get((Eo *) obj);
2069 }
2070
2071 EOLIAN static Eina_Bool
_elm_fileselector_elm_interface_fileselector_folder_only_get(const Eo * obj EINA_UNUSED,Elm_Fileselector_Data * sd)2072 _elm_fileselector_elm_interface_fileselector_folder_only_get(const Eo *obj EINA_UNUSED, Elm_Fileselector_Data *sd)
2073 {
2074 return sd->only_folder;
2075 }
2076
2077 EOLIAN static void
_elm_fileselector_buttons_ok_cancel_set(Eo * obj,Elm_Fileselector_Data * sd,Eina_Bool visible)2078 _elm_fileselector_buttons_ok_cancel_set(Eo *obj, Elm_Fileselector_Data *sd, Eina_Bool visible)
2079 {
2080 Evas_Object *bt;
2081
2082 visible = !!visible;
2083
2084 if (!visible == !sd->ok_button) return;
2085
2086 if (visible)
2087 {
2088 // ok btn
2089 bt = elm_button_add(obj);
2090 efl_ui_mirrored_automatic_set(bt, EINA_FALSE);
2091 elm_object_domain_translatable_text_set(bt, PACKAGE, N_("OK"));
2092 evas_object_smart_callback_add(bt, "clicked", _ok, obj);
2093
2094 sd->ok_button = bt;
2095 elm_object_part_content_set(obj, "elm.swallow.ok", sd->ok_button);
2096
2097 // cancel btn
2098 bt = elm_button_add(obj);
2099 efl_ui_mirrored_automatic_set(bt, EINA_FALSE);
2100 elm_object_domain_translatable_text_set(bt, PACKAGE, N_("Cancel"));
2101 evas_object_smart_callback_add(bt, "clicked", _canc, obj);
2102 sd->cancel_button = bt;
2103 elm_object_part_content_set(obj, "elm.swallow.cancel", sd->cancel_button);
2104 }
2105 else
2106 {
2107 ELM_SAFE_FREE(sd->cancel_button, evas_object_del);
2108 ELM_SAFE_FREE(sd->ok_button, evas_object_del);
2109 }
2110
2111 _focus_chain_update(obj, sd);
2112 }
2113
2114 EOLIAN static Eina_Bool
_elm_fileselector_buttons_ok_cancel_get(const Eo * obj EINA_UNUSED,Elm_Fileselector_Data * sd)2115 _elm_fileselector_buttons_ok_cancel_get(const Eo *obj EINA_UNUSED, Elm_Fileselector_Data *sd)
2116 {
2117 return sd->ok_button ? EINA_TRUE : EINA_FALSE;
2118 }
2119
2120 EAPI void
elm_fileselector_expandable_set(Evas_Object * obj,Eina_Bool expand)2121 elm_fileselector_expandable_set(Evas_Object *obj,
2122 Eina_Bool expand)
2123 {
2124 ELM_FILESELECTOR_INTERFACE_CHECK(obj);
2125 elm_interface_fileselector_expandable_set(obj, expand);
2126 }
2127
2128 EOLIAN static void
_elm_fileselector_elm_interface_fileselector_expandable_set(Eo * obj,Elm_Fileselector_Data * sd,Eina_Bool expand)2129 _elm_fileselector_elm_interface_fileselector_expandable_set(Eo *obj, Elm_Fileselector_Data *sd, Eina_Bool expand)
2130 {
2131 sd->expand = !!expand;
2132
2133 if (sd->model)
2134 {
2135 _populate(obj, sd->model, NULL, NULL);
2136 }
2137 }
2138
2139 EAPI Eina_Bool
elm_fileselector_expandable_get(const Evas_Object * obj)2140 elm_fileselector_expandable_get(const Evas_Object *obj)
2141 {
2142 ELM_FILESELECTOR_INTERFACE_CHECK(obj, EINA_FALSE);
2143 return elm_interface_fileselector_expandable_get((Eo *) obj);
2144 }
2145
2146 EOLIAN static Eina_Bool
_elm_fileselector_elm_interface_fileselector_expandable_get(const Eo * obj EINA_UNUSED,Elm_Fileselector_Data * sd)2147 _elm_fileselector_elm_interface_fileselector_expandable_get(const Eo *obj EINA_UNUSED, Elm_Fileselector_Data *sd)
2148 {
2149 return sd->expand;
2150 }
2151
2152 EAPI void
elm_fileselector_path_set(Evas_Object * obj,const char * _path)2153 elm_fileselector_path_set(Evas_Object *obj,
2154 const char *_path)
2155 {
2156 ELM_FILESELECTOR_INTERFACE_CHECK(obj);
2157 const Efl_Class *cls = efl_class_get(obj);
2158 if (cls == ELM_FILESELECTOR_CLASS)
2159 _elm_fileselector_path_set_internal(obj, _path);
2160 else if (cls == ELM_FILESELECTOR_ENTRY_CLASS)
2161 _elm_fileselector_entry_path_set_internal(obj, _path);
2162 else if (cls == ELM_FILESELECTOR_BUTTON_CLASS)
2163 _elm_fileselector_button_path_set_internal(obj, _path);
2164 else
2165 ERR("Unknown Elm.Fileselector class");
2166 }
2167
2168 void
_elm_fileselector_path_set_internal(Evas_Object * obj,const char * _path)2169 _elm_fileselector_path_set_internal(Evas_Object *obj, const char *_path)
2170 {
2171 Efl_Io_Model *model = efl_add_ref(EFL_IO_MODEL_CLASS, obj,
2172 efl_io_model_path_set(efl_added, _path),
2173 efl_loop_model_volatile_make(efl_added));
2174 if (!model)
2175 {
2176 ERR("Efl.Model allocation error");
2177 return;
2178 }
2179 efl_ui_view_model_set(obj, model);
2180 }
2181
2182 EOLIAN static void
_elm_fileselector_efl_ui_view_model_set(Eo * obj,Elm_Fileselector_Data * sd EINA_UNUSED,Efl_Model * model)2183 _elm_fileselector_efl_ui_view_model_set(Eo *obj, Elm_Fileselector_Data *sd EINA_UNUSED, Efl_Model *model)
2184 {
2185 if (!efl_isa(model, EFL_IO_MODEL_CLASS))
2186 return ;
2187 _populate(obj, model, NULL, NULL);
2188 }
2189
2190 EAPI const char *
elm_fileselector_path_get(const Evas_Object * obj)2191 elm_fileselector_path_get(const Evas_Object *obj)
2192 {
2193 ELM_FILESELECTOR_INTERFACE_CHECK(obj, NULL);
2194 const Efl_Class *cls = efl_class_get(obj);
2195 if (cls == ELM_FILESELECTOR_CLASS)
2196 return _elm_fileselector_path_get_internal(obj);
2197 else if (cls == ELM_FILESELECTOR_ENTRY_CLASS)
2198 return _elm_fileselector_entry_path_get_internal(obj);
2199 else if (cls == ELM_FILESELECTOR_BUTTON_CLASS)
2200 return _elm_fileselector_button_path_get_internal(obj);
2201 else
2202 {
2203 ERR("Unknown Elm.Fileselector class");
2204 return NULL;
2205 }
2206 }
2207
2208 const char *
_elm_fileselector_path_get_internal(const Evas_Object * obj)2209 _elm_fileselector_path_get_internal(const Evas_Object *obj)
2210 {
2211 ELM_FILESELECTOR_DATA_GET(obj, sd);
2212 return sd->path;
2213 }
2214
2215 EOLIAN static Efl_Model *
_elm_fileselector_efl_ui_view_model_get(const Eo * obj EINA_UNUSED,Elm_Fileselector_Data * sd)2216 _elm_fileselector_efl_ui_view_model_get(const Eo *obj EINA_UNUSED, Elm_Fileselector_Data *sd)
2217 {
2218 return sd->model;
2219 }
2220
2221 EAPI void
elm_fileselector_mode_set(Evas_Object * obj,Elm_Fileselector_Mode mode)2222 elm_fileselector_mode_set(Evas_Object *obj,
2223 Elm_Fileselector_Mode mode)
2224 {
2225 ELM_FILESELECTOR_INTERFACE_CHECK(obj);
2226 elm_interface_fileselector_mode_set(obj, mode);
2227 }
2228
2229 EOLIAN static void
_elm_fileselector_elm_interface_fileselector_mode_set(Eo * obj,Elm_Fileselector_Data * sd,Elm_Fileselector_Mode mode)2230 _elm_fileselector_elm_interface_fileselector_mode_set(Eo *obj, Elm_Fileselector_Data *sd, Elm_Fileselector_Mode mode)
2231 {
2232 Evas_Object *old;
2233
2234 if (mode == sd->mode) return;
2235
2236 old = elm_layout_content_unset(obj, "elm.swallow.files");
2237
2238 if (mode == ELM_FILESELECTOR_LIST)
2239 {
2240 sd->files_view = _files_list_add(obj);
2241 if (sd->multi)
2242 elm_genlist_multi_select_set(sd->files_view, EINA_TRUE);
2243 }
2244 else
2245 {
2246 sd->files_view = _files_grid_add(obj);
2247 if (sd->multi)
2248 elm_gengrid_multi_select_set(sd->files_view, EINA_TRUE);
2249 }
2250
2251 elm_layout_content_set(obj, "elm.swallow.files", sd->files_view);
2252
2253 evas_object_del(old);
2254
2255 sd->mode = mode;
2256
2257 efl_ui_widget_theme_apply(obj);
2258 if (sd->model)
2259 {
2260 _populate(obj, sd->model, NULL, NULL);
2261 }
2262 }
2263
2264 EAPI Elm_Fileselector_Mode
elm_fileselector_mode_get(const Evas_Object * obj)2265 elm_fileselector_mode_get(const Evas_Object *obj)
2266 {
2267 ELM_FILESELECTOR_INTERFACE_CHECK(obj, ELM_FILESELECTOR_LAST);
2268 return elm_interface_fileselector_mode_get((Eo *) obj);
2269 }
2270
2271 EOLIAN static Elm_Fileselector_Mode
_elm_fileselector_elm_interface_fileselector_mode_get(const Eo * obj EINA_UNUSED,Elm_Fileselector_Data * sd)2272 _elm_fileselector_elm_interface_fileselector_mode_get(const Eo *obj EINA_UNUSED, Elm_Fileselector_Data *sd)
2273 {
2274 return sd->mode;
2275 }
2276
2277 EAPI void
elm_fileselector_multi_select_set(Evas_Object * obj,Eina_Bool multi)2278 elm_fileselector_multi_select_set(Evas_Object *obj, Eina_Bool multi)
2279 {
2280 ELM_FILESELECTOR_INTERFACE_CHECK(obj);
2281 elm_interface_fileselector_multi_select_set(obj, multi);
2282 }
2283
2284 EOLIAN static void
_elm_fileselector_elm_interface_fileselector_multi_select_set(Eo * obj EINA_UNUSED,Elm_Fileselector_Data * sd,Eina_Bool multi)2285 _elm_fileselector_elm_interface_fileselector_multi_select_set(Eo *obj EINA_UNUSED, Elm_Fileselector_Data *sd, Eina_Bool multi)
2286 {
2287 multi = !!multi;
2288 if (sd->multi == multi) return;
2289 sd->multi = multi;
2290
2291 if (sd->mode == ELM_FILESELECTOR_LIST)
2292 elm_genlist_multi_select_set(sd->files_view, multi);
2293 else
2294 elm_gengrid_multi_select_set(sd->files_view, multi);
2295
2296 if (!sd->multi)
2297 {
2298 _clear_selections(sd, NULL);
2299
2300 sd->multi_selection = eina_list_free(sd->multi_selection);
2301 }
2302 else
2303 {
2304 const Eina_List *selected_items, *li;
2305 const Elm_Object_Item *it;
2306
2307 if (sd->mode == ELM_FILESELECTOR_LIST)
2308 selected_items = elm_genlist_selected_items_get(sd->files_view);
2309 else
2310 selected_items = elm_gengrid_selected_items_get(sd->files_view);
2311
2312 EINA_LIST_FOREACH(selected_items, li, it)
2313 {
2314 sd->multi_selection = eina_list_append(sd->multi_selection, it);
2315 }
2316 }
2317 }
2318
2319 EAPI Eina_Bool
elm_fileselector_multi_select_get(const Evas_Object * obj)2320 elm_fileselector_multi_select_get(const Evas_Object *obj)
2321 {
2322 ELM_FILESELECTOR_INTERFACE_CHECK(obj, EINA_FALSE);
2323 return elm_interface_fileselector_multi_select_get((Eo *) obj);
2324 }
2325
2326 EOLIAN static Eina_Bool
_elm_fileselector_elm_interface_fileselector_multi_select_get(const Eo * obj EINA_UNUSED,Elm_Fileselector_Data * sd)2327 _elm_fileselector_elm_interface_fileselector_multi_select_get(const Eo *obj EINA_UNUSED, Elm_Fileselector_Data *sd)
2328 {
2329 return sd->multi;
2330 }
2331
2332 static Elm_Fileselector_Item_Data *
_selected_item_data_get(Elm_Fileselector_Data * sd)2333 _selected_item_data_get(Elm_Fileselector_Data *sd)
2334 {
2335 if (sd->mode == ELM_FILESELECTOR_LIST)
2336 {
2337 Elm_Object_Item *gl_it = elm_genlist_selected_item_get(sd->files_view);
2338
2339 if (gl_it) return elm_object_item_data_get(gl_it);
2340 }
2341 else
2342 {
2343 Elm_Object_Item *gg_it = elm_gengrid_selected_item_get(sd->files_view);
2344
2345 if (gg_it) return elm_object_item_data_get(gg_it);
2346 }
2347 return NULL;
2348 }
2349
2350 EAPI const char *
elm_fileselector_selected_get(const Evas_Object * obj)2351 elm_fileselector_selected_get(const Evas_Object *obj)
2352 {
2353 ELM_FILESELECTOR_INTERFACE_CHECK(obj, NULL);
2354
2355 const Efl_Class *cls = efl_class_get(obj);
2356 if (cls == ELM_FILESELECTOR_CLASS)
2357 return _elm_fileselector_selected_get_internal(obj);
2358 else if (cls == ELM_FILESELECTOR_ENTRY_CLASS)
2359 return _elm_fileselector_entry_selected_get_internal(obj);
2360 else if (cls == ELM_FILESELECTOR_BUTTON_CLASS)
2361 return _elm_fileselector_button_selected_get_internal(obj);
2362 else
2363 {
2364 ERR("Unknown Elm.Fileselector class");
2365 return NULL;
2366 }
2367 }
2368
2369 const char *
_elm_fileselector_selected_get_internal(const Evas_Object * obj)2370 _elm_fileselector_selected_get_internal(const Evas_Object *obj)
2371 {
2372 ELM_FILESELECTOR_DATA_GET(obj, sd);
2373 if (!sd->path) return NULL;
2374 if (sd->target)
2375 {
2376 return _io_path_get(sd->target);
2377 }
2378
2379 Elm_Fileselector_Item_Data *it_data = _selected_item_data_get(sd);
2380 if (it_data)
2381 return it_data->path;
2382
2383 return sd->path;
2384 }
2385
2386 EOLIAN static Efl_Model *
_elm_fileselector_elm_interface_fileselector_selected_model_get(const Eo * fs EINA_UNUSED,Elm_Fileselector_Data * sd)2387 _elm_fileselector_elm_interface_fileselector_selected_model_get(const Eo *fs EINA_UNUSED, Elm_Fileselector_Data *sd)
2388 {
2389 if (!sd->model)
2390 {
2391 return NULL;
2392 }
2393
2394 Elm_Fileselector_Item_Data *it_data = _selected_item_data_get(sd);
2395 if (it_data)
2396 return it_data->model;
2397
2398 return sd->model;
2399 }
2400
2401 EAPI Eina_Bool
elm_fileselector_selected_set(Evas_Object * obj,const char * _path)2402 elm_fileselector_selected_set(Evas_Object *obj,
2403 const char *_path)
2404 {
2405 ELM_FILESELECTOR_INTERFACE_CHECK(obj, EINA_FALSE);
2406
2407 const Efl_Class *cls = efl_class_get(obj);
2408 if (cls == ELM_FILESELECTOR_CLASS)
2409 return _elm_fileselector_selected_set_internal(obj, _path);
2410 else if (cls == ELM_FILESELECTOR_ENTRY_CLASS)
2411 return _elm_fileselector_entry_selected_set_internal(obj, _path);
2412 else if (cls == ELM_FILESELECTOR_BUTTON_CLASS)
2413 return _elm_fileselector_button_selected_set_internal(obj, _path);
2414 else
2415 {
2416 ERR("Unknown Elm.Fileselector class");
2417 return EINA_FALSE;
2418 }
2419 }
2420
2421 static void
_properties_ready(void * data,const Efl_Event * ev)2422 _properties_ready(void *data, const Efl_Event *ev)
2423 {
2424 Evas_Object *obj = data;
2425 Efl_Model_Property_Event *event = ev->info;
2426 const char *property = NULL;
2427 Eina_Array_Iterator iterator;
2428 unsigned int i;
2429
2430 ELM_FILESELECTOR_DATA_GET(obj, pd);
2431
2432 EINA_ARRAY_ITER_NEXT(event->changed_properties, i, property, iterator)
2433 if (!strcmp(property, "is_dir"))
2434 {
2435 Eina_Value *value;
2436 Eina_Bool is_dir = EINA_FALSE;
2437
2438 value = efl_model_property_get(ev->object, "is_dir");
2439 if (!eina_value_type_get(value))
2440 {
2441 ERR("Empty type for 'is_dir'");
2442 return;
2443 }
2444 if (eina_value_type_get(value) != EINA_VALUE_TYPE_BOOL)
2445 {
2446 ERR("Unexpected type for 'is_dir': '%s' with value '%s'.", eina_value_type_get(value)->name, eina_value_to_string(value));
2447 return ;
2448 }
2449
2450 efl_event_callback_del(ev->object, EFL_MODEL_EVENT_PROPERTIES_CHANGED, _properties_ready, obj);
2451
2452 eina_value_bool_get(value, &is_dir);
2453 pd->target_ready = EINA_TRUE;
2454 if (!is_dir)
2455 {
2456 Efl_Model *parent;
2457 const char *path = _io_path_get(ev->object);
2458 char *dir = ecore_file_dir_get(path);
2459
2460 parent = efl_add_ref(EFL_IO_MODEL_CLASS, obj,
2461 efl_io_model_path_set(efl_added, dir),
2462 efl_event_callback_array_add(efl_added, noref_death(), NULL));
2463 if (!parent)
2464 {
2465 ERR("Could not create model for '%s'.", dir);
2466 _reset_target(pd);
2467 free(dir);
2468 return ;
2469 }
2470 efl_model_children_count_get(parent);
2471
2472 _populate(obj, parent, NULL, ev->object);
2473 efl_unref(parent);
2474 free(dir);
2475 }
2476 else
2477 {
2478 efl_model_children_count_get(ev->object);
2479 _populate(obj, ev->object, NULL, NULL);
2480 }
2481 return ;
2482 }
2483 }
2484
2485 Eina_Bool
_elm_fileselector_selected_set_internal(Evas_Object * obj,const char * path)2486 _elm_fileselector_selected_set_internal(Evas_Object *obj, const char *path)
2487 {
2488 Eina_Value *value;
2489 struct stat st;
2490
2491 ELM_FILESELECTOR_INTERFACE_CHECK(obj, EINA_FALSE);
2492 ELM_FILESELECTOR_DATA_GET(obj, pd);
2493
2494 _reset_target(pd);
2495
2496 if (stat(path, &st)) return EINA_FALSE;
2497
2498 pd->target_ready = EINA_FALSE;
2499 pd->target = efl_add_ref(EFL_IO_MODEL_CLASS, obj, efl_io_model_path_set(efl_added, path),
2500 efl_event_callback_array_add(efl_added, noref_death(), NULL));
2501 if (!pd->target)
2502 {
2503 ERR("Could not create model for '%s'.", path);
2504 return EINA_FALSE;
2505 }
2506
2507 efl_event_callback_add(pd->target, EFL_MODEL_EVENT_PROPERTIES_CHANGED, _properties_ready, obj);
2508 value = efl_model_property_get(pd->target, "is_dir");
2509 if (!eina_value_type_get(value))
2510 {
2511 ERR("Empty type for 'is_dir'");
2512 goto clean_up;
2513 }
2514 if (eina_value_type_get(value) == EINA_VALUE_TYPE_ERROR)
2515 {
2516 Eina_Error err = 0;
2517
2518 eina_value_error_get(value, &err);
2519 if (err != EAGAIN)
2520 {
2521 ERR("Unexpected error '%s' when setting path '%s'.", eina_value_to_string(value), path);
2522 goto clean_up;
2523 }
2524
2525 return EINA_TRUE;
2526 }
2527
2528 ERR("Unexpected value '%s' when setting path '%s'.", eina_value_to_string(value), path);
2529
2530 clean_up:
2531 _reset_target(pd);
2532 return EINA_FALSE;
2533 }
2534
2535 EOLIAN static Eina_Bool
_elm_fileselector_elm_interface_fileselector_selected_model_set(Eo * obj,Elm_Fileselector_Data * pd,Efl_Model * model)2536 _elm_fileselector_elm_interface_fileselector_selected_model_set(Eo *obj, Elm_Fileselector_Data *pd, Efl_Model *model)
2537 {
2538 Eina_Value *value = NULL;
2539 Eina_Bool dir = EINA_FALSE;
2540
2541 if (!efl_isa(model, EFL_IO_MODEL_CLASS)) return EINA_FALSE;
2542
2543 efl_event_callback_del(pd->target, EFL_MODEL_EVENT_PROPERTIES_CHANGED, _properties_ready, obj);
2544 efl_replace(&pd->target, model);
2545
2546 if (!model) return EINA_TRUE;
2547
2548 efl_event_callback_add(pd->target, EFL_MODEL_EVENT_PROPERTIES_CHANGED, _properties_ready, obj);
2549 value = efl_model_property_get(pd->target, "is_dir");
2550 if (!eina_value_type_get(value))
2551 {
2552 ERR("Empty type for 'is_dir'");
2553 goto clean_up;
2554 }
2555 if (eina_value_type_get(value) == EINA_VALUE_TYPE_ERROR)
2556 {
2557 Eina_Error err = 0;
2558
2559 eina_value_error_get(value, &err);
2560 if (err != EAGAIN)
2561 {
2562 ERR("Unexpected error '%s' when setting path '%s'.", eina_value_to_string(value), _io_path_get(pd->target));
2563 goto clean_up;
2564 }
2565
2566 return EINA_TRUE;
2567 }
2568
2569 if (eina_value_type_get(value) != EINA_VALUE_TYPE_BOOL)
2570 {
2571 ERR("Unexpected type for 'is_dir': '%s' with value '%s'.", eina_value_type_get(value)->name, eina_value_to_string(value));
2572 goto clean_up;
2573 }
2574
2575 efl_event_callback_del(pd->target, EFL_MODEL_EVENT_PROPERTIES_CHANGED, _properties_ready, obj);
2576
2577 eina_value_bool_get(value, &dir);
2578
2579 if (!dir)
2580 {
2581 Efl_Model *parent;
2582 const char *path = _io_path_get(pd->target);
2583 char *d = ecore_file_dir_get(path);
2584
2585 parent = efl_add_ref(EFL_IO_MODEL_CLASS, obj, efl_io_model_path_set(efl_added, d),
2586 efl_event_callback_array_add(efl_added, noref_death(), NULL));
2587 if (!parent)
2588 {
2589 ERR("Could not create model for '%s'.", d);
2590 free(d);
2591 goto clean_up;
2592 }
2593 efl_model_children_count_get(parent);
2594
2595 _populate(obj, parent, NULL, pd->target);
2596 efl_unref(parent);
2597 free(d);
2598 }
2599 else
2600 {
2601 efl_model_children_count_get(pd->target);
2602 _populate(obj, pd->target, NULL, NULL);
2603 }
2604
2605 return EINA_TRUE;
2606
2607 clean_up:
2608 _reset_target(pd);
2609 return EINA_FALSE;
2610 }
2611
2612 EAPI const Eina_List *
elm_fileselector_selected_paths_get(const Evas_Object * obj)2613 elm_fileselector_selected_paths_get(const Evas_Object* obj)
2614 {
2615 ELM_FILESELECTOR_INTERFACE_CHECK(obj, NULL);
2616
2617 const Efl_Class *cls = efl_class_get(obj);
2618 if (cls == ELM_FILESELECTOR_CLASS)
2619 return _elm_fileselector_selected_paths_get_internal(obj);
2620 else if (cls == ELM_FILESELECTOR_BUTTON_CLASS)
2621 return _elm_fileselector_button_selected_paths_get_internal(obj);
2622 else
2623 ERR("Unknown Elm.Fileselector class");
2624 return NULL;
2625 }
2626
2627 const Eina_List *
_elm_fileselector_selected_paths_get_internal(const Evas_Object * obj)2628 _elm_fileselector_selected_paths_get_internal(const Evas_Object* obj)
2629 {
2630 ELM_FILESELECTOR_INTERFACE_CHECK(obj, NULL);
2631 Eina_List *l;
2632 Elm_Object_Item *item;
2633 ELM_FILESELECTOR_DATA_GET(obj, sd);
2634
2635 if (!sd->multi)
2636 return NULL;
2637
2638 if (sd->multi_selection_tmp)
2639 {
2640 sd->multi_selection_tmp = eina_list_free(sd->multi_selection_tmp);
2641 }
2642
2643 EINA_LIST_FOREACH(sd->multi_selection, l, item)
2644 {
2645 Elm_Fileselector_Item_Data *it_data = elm_object_item_data_get(item);
2646 sd->multi_selection_tmp = eina_list_append(sd->multi_selection_tmp, it_data->path);
2647 }
2648 return sd->multi_selection_tmp;
2649 }
2650
2651 EOLIAN static const Eina_List*
_elm_fileselector_elm_interface_fileselector_selected_models_get(const Eo * obj EINA_UNUSED,Elm_Fileselector_Data * sd)2652 _elm_fileselector_elm_interface_fileselector_selected_models_get(const Eo *obj EINA_UNUSED, Elm_Fileselector_Data *sd)
2653 {
2654 Eina_List *l;
2655 Elm_Object_Item *item;
2656 if (!sd->multi)
2657 return NULL;
2658
2659 if (sd->multi_selection_tmp)
2660 {
2661 sd->multi_selection_tmp = eina_list_free(sd->multi_selection_tmp);
2662 }
2663
2664 EINA_LIST_FOREACH(sd->multi_selection, l, item)
2665 {
2666 Elm_Fileselector_Item_Data *it_data = elm_object_item_data_get(item);
2667 sd->multi_selection_tmp = eina_list_append(sd->multi_selection_tmp, it_data->model);
2668 }
2669 return sd->multi_selection_tmp;
2670 }
2671
2672 EAPI const char *
elm_fileselector_current_name_get(const Evas_Object * obj)2673 elm_fileselector_current_name_get(const Evas_Object *obj)
2674 {
2675 ELM_FILESELECTOR_INTERFACE_CHECK(obj, NULL);
2676 const char *ret = NULL;
2677 ret = elm_interface_fileselector_current_name_get((Eo *) obj);
2678 return ret;
2679 }
2680
2681 EOLIAN static const char *
_elm_fileselector_elm_interface_fileselector_current_name_get(const Eo * obj EINA_UNUSED,Elm_Fileselector_Data * sd)2682 _elm_fileselector_elm_interface_fileselector_current_name_get(const Eo *obj EINA_UNUSED, Elm_Fileselector_Data *sd)
2683 {
2684 return elm_object_text_get(sd->name_entry);
2685 }
2686
2687 EAPI void
elm_fileselector_current_name_set(Evas_Object * obj,const char * name)2688 elm_fileselector_current_name_set(Evas_Object *obj,
2689 const char *name)
2690 {
2691 ELM_FILESELECTOR_INTERFACE_CHECK(obj);
2692 elm_interface_fileselector_current_name_set((Eo *) obj, name);
2693 }
2694
2695 EOLIAN static void
_elm_fileselector_elm_interface_fileselector_current_name_set(Eo * obj EINA_UNUSED,Elm_Fileselector_Data * sd,const char * name)2696 _elm_fileselector_elm_interface_fileselector_current_name_set(Eo *obj EINA_UNUSED, Elm_Fileselector_Data *sd, const char *name)
2697 {
2698 elm_object_text_set(sd->name_entry, name);
2699 }
2700
2701 static Elm_Fileselector_Filter *
_filter_add(Elm_Fileselector_Data * sd,const char * filter_name)2702 _filter_add(Elm_Fileselector_Data *sd, const char *filter_name)
2703 {
2704 Elm_Fileselector_Filter *ff;
2705 ff = calloc(1, sizeof(Elm_Fileselector_Filter));
2706 if (!ff) return NULL;
2707
2708 ff->filter_name = eina_stringshare_add(filter_name);
2709 ff->sd = sd;
2710
2711 return ff;
2712 }
2713
2714 EAPI Eina_Bool
elm_fileselector_mime_types_filter_append(Evas_Object * obj,const char * mime_type,const char * filter_name)2715 elm_fileselector_mime_types_filter_append(Evas_Object *obj, const char *mime_type, const char *filter_name)
2716 {
2717 ELM_FILESELECTOR_CHECK(obj) EINA_FALSE;
2718 return elm_interface_fileselector_mime_types_filter_append(obj, mime_type, filter_name);
2719 }
2720
2721 EOLIAN static Eina_Bool
_elm_fileselector_elm_interface_fileselector_mime_types_filter_append(Eo * obj,Elm_Fileselector_Data * sd,const char * mime_types,const char * filter_name)2722 _elm_fileselector_elm_interface_fileselector_mime_types_filter_append(Eo *obj, Elm_Fileselector_Data *sd, const char *mime_types, const char *filter_name)
2723 {
2724 Elm_Fileselector_Filter *ff;
2725 char buf[1024];
2726
2727 if (!mime_types) return EINA_FALSE;
2728
2729 ff = _filter_add(sd, filter_name ? filter_name : mime_types);
2730 if (!ff) return EINA_FALSE;
2731
2732 ff->filter_type = ELM_FILESELECTOR_MIME_FILTER;
2733
2734 ff->filter.mime_types = eina_str_split(mime_types, ",", 0);
2735
2736 if (!sd->filter_list)
2737 {
2738 sd->current_filter = ff;
2739 sd->filter_hoversel = elm_hoversel_add(obj);
2740 elm_object_text_set(sd->filter_hoversel, ff->filter_name);
2741 snprintf(buf, sizeof(buf), "fileselector/actions/%s", elm_widget_style_get(obj));
2742 elm_widget_style_set(sd->filter_hoversel, buf);
2743 elm_object_part_content_set(obj, "elm.swallow.filters", sd->filter_hoversel);
2744 }
2745 elm_hoversel_item_add(sd->filter_hoversel, ff->filter_name, NULL, ELM_ICON_NONE, _current_filter_changed, ff);
2746
2747 sd->filter_list = eina_list_append(sd->filter_list, ff);
2748
2749 if (sd->model)
2750 {
2751 _populate(obj, sd->model, NULL, NULL);
2752 }
2753
2754 return EINA_TRUE;
2755 }
2756
2757 EAPI Eina_Bool
elm_fileselector_custom_filter_append(Evas_Object * obj,Elm_Fileselector_Filter_Func func,void * data,const char * filter_name)2758 elm_fileselector_custom_filter_append(Evas_Object *obj, Elm_Fileselector_Filter_Func func, void *data, const char *filter_name)
2759 {
2760 ELM_FILESELECTOR_INTERFACE_CHECK(obj, EINA_FALSE);
2761 return elm_interface_fileselector_custom_filter_append(obj, func, data, filter_name);
2762 }
2763
2764 EOLIAN static Eina_Bool
_elm_fileselector_elm_interface_fileselector_custom_filter_append(Eo * obj,Elm_Fileselector_Data * sd,Elm_Fileselector_Filter_Func func,void * data,const char * filter_name)2765 _elm_fileselector_elm_interface_fileselector_custom_filter_append(Eo *obj, Elm_Fileselector_Data *sd, Elm_Fileselector_Filter_Func func, void *data, const char *filter_name)
2766 {
2767 Elm_Fileselector_Filter *ff;
2768 Elm_Fileselector_Custom_Filter *custom_filter;
2769 char buf[1024];
2770
2771 if (!func) return EINA_FALSE;
2772
2773 custom_filter = calloc(1, sizeof(Elm_Fileselector_Custom_Filter));
2774 if (!custom_filter) return EINA_FALSE;
2775
2776 ff = _filter_add(sd, filter_name ? filter_name : "custom");
2777 if (!ff)
2778 {
2779 free(custom_filter);
2780 return EINA_FALSE;
2781 }
2782
2783 ff->filter_type = ELM_FILESELECTOR_CUSTOM_FILTER;
2784 ff->filter.custom = custom_filter;
2785 ff->filter.custom->func = func;
2786 ff->filter.custom->data = data;
2787
2788 if (!sd->filter_list)
2789 {
2790 sd->current_filter = ff;
2791 sd->filter_hoversel = elm_hoversel_add(obj);
2792 elm_object_text_set(sd->filter_hoversel, ff->filter_name);
2793 snprintf(buf, sizeof(buf), "fileselector/actions/%s", elm_widget_style_get(obj));
2794 elm_widget_style_set(sd->filter_hoversel, buf);
2795 elm_object_part_content_set(obj, "elm.swallow.filters", sd->filter_hoversel);
2796 }
2797 elm_hoversel_item_add(sd->filter_hoversel, ff->filter_name, NULL, ELM_ICON_NONE, _current_filter_changed, ff);
2798
2799 sd->filter_list = eina_list_append(sd->filter_list, ff);
2800
2801 if (sd->model)
2802 {
2803 _populate(obj, sd->model, NULL, NULL);
2804 }
2805
2806 return EINA_TRUE;
2807 }
2808
2809 EAPI void
elm_fileselector_filters_clear(Evas_Object * obj)2810 elm_fileselector_filters_clear(Evas_Object *obj)
2811 {
2812 ELM_FILESELECTOR_INTERFACE_CHECK(obj);
2813 elm_interface_fileselector_filters_clear(obj);
2814 }
2815
2816 EOLIAN static void
_elm_fileselector_elm_interface_fileselector_filters_clear(Eo * obj,Elm_Fileselector_Data * sd)2817 _elm_fileselector_elm_interface_fileselector_filters_clear(Eo *obj, Elm_Fileselector_Data *sd)
2818 {
2819 Elm_Fileselector_Filter *filter;
2820
2821 EINA_LIST_FREE(sd->filter_list, filter)
2822 {
2823 eina_stringshare_del(filter->filter_name);
2824
2825 if (filter->filter_type == ELM_FILESELECTOR_MIME_FILTER)
2826 {
2827 free(filter->filter.mime_types[0]);
2828 free(filter->filter.mime_types);
2829 }
2830 else
2831 free(filter->filter.custom);
2832
2833 free(filter);
2834 }
2835
2836 ELM_SAFE_FREE(sd->filter_hoversel, evas_object_del);
2837
2838 if (sd->model)
2839 {
2840 _populate(obj, sd->model, NULL, NULL);
2841 }
2842 }
2843
2844 EAPI void
elm_fileselector_hidden_visible_set(Evas_Object * obj,Eina_Bool visible)2845 elm_fileselector_hidden_visible_set(Evas_Object *obj, Eina_Bool visible)
2846 {
2847 ELM_FILESELECTOR_INTERFACE_CHECK(obj);
2848 elm_interface_fileselector_hidden_visible_set(obj, visible);
2849 }
2850
2851 EOLIAN static void
_elm_fileselector_elm_interface_fileselector_hidden_visible_set(Eo * obj EINA_UNUSED,Elm_Fileselector_Data * sd,Eina_Bool visible)2852 _elm_fileselector_elm_interface_fileselector_hidden_visible_set(Eo *obj EINA_UNUSED, Elm_Fileselector_Data *sd, Eina_Bool visible)
2853 {
2854 visible = !!visible;
2855 if (sd->hidden_visible == visible) return;
2856 sd->hidden_visible = visible;
2857
2858 _clear_selections(sd, NULL);
2859
2860 if (sd->model)
2861 {
2862 _populate(obj, sd->model, NULL, NULL);
2863 }
2864 }
2865
2866 EAPI Eina_Bool
elm_fileselector_hidden_visible_get(const Evas_Object * obj)2867 elm_fileselector_hidden_visible_get(const Evas_Object *obj)
2868 {
2869 ELM_FILESELECTOR_INTERFACE_CHECK(obj, EINA_FALSE);
2870 return elm_interface_fileselector_hidden_visible_get((Eo *) obj);
2871 }
2872
2873 EOLIAN static Eina_Bool
_elm_fileselector_elm_interface_fileselector_hidden_visible_get(const Eo * obj EINA_UNUSED,Elm_Fileselector_Data * sd)2874 _elm_fileselector_elm_interface_fileselector_hidden_visible_get(const Eo *obj EINA_UNUSED, Elm_Fileselector_Data *sd)
2875 {
2876 return sd->hidden_visible;
2877 }
2878
2879 EAPI void
elm_fileselector_thumbnail_size_set(Evas_Object * obj,Evas_Coord w,Evas_Coord h)2880 elm_fileselector_thumbnail_size_set(Evas_Object *obj,
2881 Evas_Coord w,
2882 Evas_Coord h)
2883 {
2884 ELM_FILESELECTOR_INTERFACE_CHECK(obj);
2885 elm_interface_fileselector_thumbnail_size_set(obj, w, h);
2886 }
2887
2888 EOLIAN static void
_elm_fileselector_elm_interface_fileselector_thumbnail_size_set(Eo * obj EINA_UNUSED,Elm_Fileselector_Data * sd,Evas_Coord w,Evas_Coord h)2889 _elm_fileselector_elm_interface_fileselector_thumbnail_size_set(Eo *obj EINA_UNUSED, Elm_Fileselector_Data *sd, Evas_Coord w, Evas_Coord h)
2890 {
2891 if (sd->thumbnail_size.w == w && sd->thumbnail_size.h == h) return;
2892
2893 if (!w || !h)
2894 w = h = ITEM_SIZE_DEFAULT;
2895
2896 sd->thumbnail_size.w = w;
2897 sd->thumbnail_size.h = h;
2898
2899 if (sd->mode == ELM_FILESELECTOR_GRID)
2900 elm_gengrid_item_size_set(sd->files_view, w, h);
2901
2902 if (sd->model)
2903 {
2904 _populate(obj, sd->model, NULL, NULL);
2905 }
2906 }
2907
2908 EAPI void
elm_fileselector_thumbnail_size_get(const Evas_Object * obj,Evas_Coord * w,Evas_Coord * h)2909 elm_fileselector_thumbnail_size_get(const Evas_Object *obj,
2910 Evas_Coord *w,
2911 Evas_Coord *h)
2912 {
2913 ELM_FILESELECTOR_INTERFACE_CHECK(obj);
2914 elm_interface_fileselector_thumbnail_size_get((Eo *) obj, w, h);
2915 }
2916
2917 EOLIAN static void
_elm_fileselector_elm_interface_fileselector_thumbnail_size_get(const Eo * obj EINA_UNUSED,Elm_Fileselector_Data * sd,Evas_Coord * w,Evas_Coord * h)2918 _elm_fileselector_elm_interface_fileselector_thumbnail_size_get(const Eo *obj EINA_UNUSED, Elm_Fileselector_Data *sd, Evas_Coord *w, Evas_Coord *h)
2919 {
2920 if (w) *w = sd->thumbnail_size.w;
2921 if (h) *h = sd->thumbnail_size.h;
2922 }
2923
2924 EAPI void
elm_fileselector_sort_method_set(Evas_Object * obj,Elm_Fileselector_Sort sort)2925 elm_fileselector_sort_method_set(Evas_Object *obj, Elm_Fileselector_Sort sort)
2926 {
2927 ELM_FILESELECTOR_INTERFACE_CHECK(obj);
2928 elm_interface_fileselector_sort_method_set(obj, sort);
2929 }
2930
2931 EOLIAN static void
_elm_fileselector_elm_interface_fileselector_sort_method_set(Eo * obj EINA_UNUSED,Elm_Fileselector_Data * sd,Elm_Fileselector_Sort sort)2932 _elm_fileselector_elm_interface_fileselector_sort_method_set(Eo *obj EINA_UNUSED, Elm_Fileselector_Data *sd, Elm_Fileselector_Sort sort)
2933 {
2934 if (sd->sort_type == sort) return;
2935 sd->sort_type = sort;
2936
2937 switch (sd->sort_type)
2938 {
2939 case ELM_FILESELECTOR_SORT_BY_FILENAME_ASC:
2940 sd->sort_method = _filename_cmp;
2941 break;
2942 case ELM_FILESELECTOR_SORT_BY_FILENAME_DESC:
2943 sd->sort_method = _filename_cmp_rev;
2944 break;
2945 case ELM_FILESELECTOR_SORT_BY_TYPE_ASC:
2946 sd->sort_method = _type_cmp;
2947 break;
2948 case ELM_FILESELECTOR_SORT_BY_TYPE_DESC:
2949 sd->sort_method = _type_cmp_rev;
2950 break;
2951 case ELM_FILESELECTOR_SORT_BY_SIZE_ASC:
2952 sd->sort_method = _size_cmp;
2953 break;
2954 case ELM_FILESELECTOR_SORT_BY_SIZE_DESC:
2955 sd->sort_method = _size_cmp_rev;
2956 break;
2957 case ELM_FILESELECTOR_SORT_BY_MODIFIED_ASC:
2958 sd->sort_method = _modified_cmp;
2959 break;
2960 case ELM_FILESELECTOR_SORT_BY_MODIFIED_DESC:
2961 sd->sort_method = _modified_cmp_rev;
2962 break;
2963 case ELM_FILESELECTOR_SORT_LAST:
2964 default:
2965 sd->sort_method = _filename_cmp;
2966 }
2967
2968 if (sd->model)
2969 {
2970 _populate(obj, sd->model, NULL, NULL);
2971 }
2972 }
2973
2974 EAPI Elm_Fileselector_Sort
elm_fileselector_sort_method_get(const Evas_Object * obj)2975 elm_fileselector_sort_method_get(const Evas_Object *obj)
2976 {
2977 ELM_FILESELECTOR_INTERFACE_CHECK(obj, ELM_FILESELECTOR_SORT_LAST);
2978 return elm_interface_fileselector_sort_method_get((Eo *) obj);
2979 }
2980
2981 EOLIAN static Elm_Fileselector_Sort
_elm_fileselector_elm_interface_fileselector_sort_method_get(const Eo * obj EINA_UNUSED,Elm_Fileselector_Data * sd)2982 _elm_fileselector_elm_interface_fileselector_sort_method_get(const Eo *obj EINA_UNUSED, Elm_Fileselector_Data *sd)
2983 {
2984 return sd->sort_type;
2985 }
2986
2987 static Eina_Bool
_elm_fileselector_text_set(Eo * obj EINA_UNUSED,Elm_Fileselector_Data * sd,const char * part,const char * label)2988 _elm_fileselector_text_set(Eo *obj EINA_UNUSED, Elm_Fileselector_Data *sd, const char *part, const char *label)
2989 {
2990 if (!part) return EINA_FALSE;
2991
2992 if (sd->ok_button && !strcmp(part, "ok"))
2993 {
2994 elm_object_text_set(sd->ok_button, label);
2995 return EINA_TRUE;
2996 }
2997 else if (sd->cancel_button && !strcmp(part, "cancel"))
2998 {
2999 elm_object_text_set(sd->cancel_button, label);
3000 return EINA_TRUE;
3001 }
3002 else
3003 {
3004 Eina_Bool int_ret = EINA_TRUE;
3005 efl_text_set(efl_part(efl_super(obj, MY_CLASS), part), label);
3006 return int_ret;
3007 }
3008
3009 return EINA_FALSE;
3010 }
3011
3012 EOLIAN static void
_elm_fileselector_class_constructor(Efl_Class * klass)3013 _elm_fileselector_class_constructor(Efl_Class *klass)
3014 {
3015 unsigned int i;
3016
3017 evas_smart_legacy_type_register(MY_CLASS_NAME_LEGACY, klass);
3018
3019 ELM_FILESELECTOR_ERROR_UNKNOWN = eina_error_msg_static_register(ELM_FILESELECTOR_ERROR_UNKNOWN_STR);
3020 ELM_FILESELECTOR_ERROR_INVALID_MODEL = eina_error_msg_static_register(ELM_FILESELECTOR_ERROR_INVALID_MODEL_STR);
3021
3022 for (i = 0; i < ELM_FILE_LAST; ++i)
3023 {
3024 list_itc[i] = elm_genlist_item_class_new();
3025 grid_itc[i] = elm_gengrid_item_class_new();
3026
3027 list_itc[i]->item_style = "default";
3028 list_itc[i]->func.text_get = grid_itc[i]->func.text_get =
3029 _itc_text_get;
3030 list_itc[i]->func.state_get = grid_itc[i]->func.state_get =
3031 _itc_state_get;
3032 list_itc[i]->func.del = grid_itc[i]->func.del = _itc_del;
3033 }
3034
3035 list_itc[ELM_DIRECTORY]->func.content_get =
3036 grid_itc[ELM_DIRECTORY]->func.content_get = _itc_icon_folder_get;
3037 list_itc[ELM_FILE_IMAGE]->func.content_get =
3038 grid_itc[ELM_FILE_IMAGE]->func.content_get = _itc_icon_image_get;
3039 list_itc[ELM_FILE_UNKNOW]->func.content_get =
3040 grid_itc[ELM_FILE_UNKNOW]->func.content_get = _itc_icon_file_get;
3041
3042 }
3043
3044 EOLIAN static void
_elm_fileselector_class_destructor(Efl_Class * klass EINA_UNUSED)3045 _elm_fileselector_class_destructor(Efl_Class *klass EINA_UNUSED)
3046 {
3047 unsigned int i;
3048
3049 for (i = 0; i < ELM_FILE_LAST; ++i)
3050 {
3051 elm_genlist_item_class_free(list_itc[i]);
3052 elm_gengrid_item_class_free(grid_itc[i]);
3053 }
3054 }
3055
3056 EOLIAN const Efl_Access_Action_Data *
_elm_fileselector_efl_access_widget_action_elm_actions_get(const Eo * obj EINA_UNUSED,Elm_Fileselector_Data * pd EINA_UNUSED)3057 _elm_fileselector_efl_access_widget_action_elm_actions_get(const Eo *obj EINA_UNUSED, Elm_Fileselector_Data *pd EINA_UNUSED)
3058 {
3059 static Efl_Access_Action_Data atspi_actions[] = {
3060 { "select", "select", NULL, _key_action_select },
3061 { "escape", "escape", NULL, _key_action_escape},
3062 { "backspace", "backspace", NULL, _key_action_backspace},
3063 { NULL, NULL, NULL, NULL}
3064 };
3065 return &atspi_actions[0];
3066 }
3067
3068 /* Internal EO APIs and hidden overrides */
3069
3070 ELM_WIDGET_KEY_DOWN_DEFAULT_IMPLEMENT(elm_fileselector, Elm_Fileselector_Data)
3071
3072 /* Efl.Part begin */
3073
3074 ELM_PART_OVERRIDE(elm_fileselector, ELM_FILESELECTOR, Elm_Fileselector_Data)
3075 ELM_PART_OVERRIDE_TEXT_SET(elm_fileselector, ELM_FILESELECTOR, Elm_Fileselector_Data)
3076 #include "elm_fileselector_part.eo.c"
3077
3078 /* Efl.Part end */
3079
3080 /* Internal EO APIs and hidden overrides */
3081
3082 #define ELM_FILESELECTOR_EXTRA_OPS \
3083 EFL_CANVAS_GROUP_ADD_DEL_OPS(elm_fileselector), \
3084 EFL_OBJECT_OP_FUNC(efl_event_callback_legacy_call, _elm_fileselector_efl_object_event_callback_legacy_call)
3085
3086 #include "elm_fileselector_eo.c"
3087