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