Merge "[Password]: New design based changes, a new style removed password mode contro...
[framework/uifw/elementary.git] / src / lib / elc_fileselector.c
1 /**
2  * @defgroup Fileselector Fileselector
3  *
4  * A fileselector is a widget that allows a user to navigate through a
5  * tree of files.  It contains buttons for Home(~) and Up(..) as well
6  * as cancel/ok buttons to confirm/cancel a selection.  This widget is
7  * currently very much in progress.
8  *
9  * TODO
10  * child elements focusing support
11  * userdefined icon/label cb
12  * show/hide/add buttons ???
13  * show/Hide hidden files
14  * double click to choose a file
15  * multiselection
16  * make variable/function names that are sensible
17  * Filter support
18  *
19  * Signals that you can add callbacks for are:
20  *
21  * "selected" - the user clicks on a file
22  * "directory,open" - the list is populated with new content.
23  *                    event_info is a directory.
24  * "done" - the user clicks on the ok or cancel button
25  */
26
27 #include <Elementary.h>
28 #include "elm_priv.h"
29
30 typedef struct _Widget_Data Widget_Data;
31
32 struct _Widget_Data
33 {
34    Evas_Object *edje;
35    Evas_Object *filename_entry;
36    Evas_Object *path_entry;
37    Evas_Object *files_list;
38    Evas_Object *files_grid;
39    Evas_Object *up_button;
40    Evas_Object *home_button;
41
42    Evas_Object *ok_button;
43    Evas_Object *cancel_button;
44
45    const char  *path;
46    const char  *selection;
47    Ecore_Idler *sel_idler;
48
49    const char  *path_separator;
50
51    Elm_Fileselector_Mode mode;
52
53    Eina_Bool    only_folder : 1;
54    Eina_Bool    expand : 1;
55 };
56
57 struct sel_data
58 {
59    Evas_Object *fs;
60    const char  *path;
61 };
62
63 Elm_Genlist_Item_Class list_itc;
64 Elm_Gengrid_Item_Class grid_itc;
65
66 static const char *widtype = NULL;
67
68 static const char SIG_DIRECTORY_OPEN[] = "directory,open";
69 static const char SIG_DONE[] = "done";
70 static const char SIG_SELECTED[] = "selected";
71 static const Evas_Smart_Cb_Description _signals[] = {
72    {SIG_DIRECTORY_OPEN, "s"},
73    {SIG_DONE, "s"},
74    {SIG_SELECTED, "s"},
75    {NULL, NULL}
76 };
77
78 static void _populate(Evas_Object      *obj,
79                       const char       *path,
80                       Elm_Genlist_Item *parent);
81 static void _do_anchors(Evas_Object *obj,
82                         const char  *path);
83
84 /***  ELEMENTARY WIDGET  ***/
85 static void
86 _del_hook(Evas_Object *obj)
87 {
88    Widget_Data *wd;
89    void *sd;
90
91    wd = elm_widget_data_get(obj);
92    if (!wd) return;
93
94    if (wd->path) eina_stringshare_del(wd->path);
95    if (wd->selection) eina_stringshare_del(wd->selection);
96    if (wd->sel_idler)
97      {
98         sd = ecore_idler_del(wd->sel_idler);
99         free(sd);
100      }
101    free(wd);
102 }
103
104 static void
105 _sizing_eval(Evas_Object *obj)
106 {
107    Widget_Data *wd = elm_widget_data_get(obj);
108    Evas_Coord minw = -1, minh = -1;
109    if (!wd) return;
110    elm_coords_finger_size_adjust(1, &minw, 1, &minh);
111    edje_object_size_min_restricted_calc(wd->edje, &minw, &minh, minw, minh);
112    evas_object_size_hint_min_set(obj, minw, minh);
113 }
114
115 static void
116 _mirrored_set(Evas_Object *obj, Eina_Bool rtl)
117 {
118    Widget_Data *wd = elm_widget_data_get(obj);
119    if (!wd) return;
120    elm_widget_mirrored_set(wd->cancel_button, rtl);
121    elm_widget_mirrored_set(wd->ok_button, rtl);
122    elm_widget_mirrored_set(wd->files_list, rtl);
123    elm_widget_mirrored_set(wd->up_button, rtl);
124    elm_widget_mirrored_set(wd->home_button, rtl);
125    edje_object_mirrored_set(wd->edje, rtl);
126 }
127
128 static void
129 _theme_hook(Evas_Object *obj)
130 {
131    Widget_Data *wd = elm_widget_data_get(obj);
132    const char *style = elm_widget_style_get(obj);
133    const char *data;
134    char buf[1024];
135
136    if (!wd) return;
137    _elm_widget_mirrored_reload(obj);
138
139    _elm_theme_object_set(obj, wd->edje, "fileselector", "base", style);
140
141    if (elm_object_disabled_get(obj))
142      edje_object_signal_emit(wd->edje, "elm,state,disabled", "elm");
143
144    data = edje_object_data_get(wd->edje, "path_separator");
145    if (data)
146      wd->path_separator = data;
147    else
148      wd->path_separator = "/";
149
150    if (!style) style = "default";
151    snprintf(buf, sizeof(buf), "fileselector/%s", style);
152
153 #define SWALLOW(part_name, object_ptn)                                \
154   if (object_ptn)                                                     \
155     {                                                                 \
156        elm_widget_style_set(object_ptn, buf);                         \
157        if (edje_object_part_swallow(wd->edje, part_name, object_ptn)) \
158          evas_object_show(object_ptn);                                \
159        else                                                           \
160          evas_object_hide(object_ptn);                                \
161     }
162    SWALLOW("elm.swallow.up", wd->up_button);
163    SWALLOW("elm.swallow.home", wd->home_button);
164
165    if (wd->mode == ELM_FILESELECTOR_LIST)
166      {
167         if (edje_object_part_swallow(wd->edje, "elm.swallow.files",
168                                      wd->files_list))
169           {
170              evas_object_show(wd->files_list);
171              evas_object_hide(wd->files_grid);
172           }
173         else
174           evas_object_hide(wd->files_list);
175      }
176    else
177      {
178         if (edje_object_part_swallow(wd->edje, "elm.swallow.files",
179                                      wd->files_grid))
180           {
181              evas_object_show(wd->files_grid);
182              evas_object_hide(wd->files_list);
183           }
184         else
185           evas_object_hide(wd->files_grid);
186      }
187
188    SWALLOW("elm.swallow.filename", wd->filename_entry);
189    SWALLOW("elm.swallow.path", wd->path_entry);
190
191    snprintf(buf, sizeof(buf), "fileselector/actions/%s", style);
192    SWALLOW("elm.swallow.cancel", wd->cancel_button);
193    SWALLOW("elm.swallow.ok", wd->ok_button);
194 #undef SWALLOW
195
196    edje_object_message_signal_process(wd->edje);
197    _mirrored_set(obj, elm_widget_mirrored_get(obj));
198    edje_object_scale_set
199      (wd->edje, elm_widget_scale_get(obj) * _elm_config->scale);
200    _sizing_eval(obj);
201 }
202
203 /***  GENLIST "MODEL"  ***/
204 static char *
205 _itc_label_get(void              *data,
206                Evas_Object *obj   __UNUSED__,
207                const char *source __UNUSED__)
208 {
209    return strdup(ecore_file_file_get(data)); /* NOTE this will be
210                                               * free() by the
211                                               * caller */
212 }
213
214 static Evas_Object *
215 _itc_icon_get(void        *data,
216               Evas_Object *obj,
217               const char  *source)
218 {
219    Evas_Object *ic;
220
221    if (!strcmp(source, "elm.swallow.icon"))
222      {
223         ic = elm_icon_add(obj);
224         if (ecore_file_is_dir((char *)data))
225           elm_icon_standard_set(ic, "folder");
226         else
227           elm_icon_standard_set(ic, "file");
228         evas_object_size_hint_aspect_set(ic, EVAS_ASPECT_CONTROL_VERTICAL,
229                                          1, 1);
230         evas_object_show(ic);
231         return ic;
232      }
233    return NULL;
234 }
235
236 static Eina_Bool
237 _itc_state_get(void *data         __UNUSED__,
238                Evas_Object *obj   __UNUSED__,
239                const char *source __UNUSED__)
240 {
241    return EINA_FALSE;
242 }
243
244 static void
245 _itc_del(void            *data,
246          Evas_Object *obj __UNUSED__)
247 {
248    eina_stringshare_del(data);
249 }
250
251 static void
252 _expand_done(void            *data,
253              Evas_Object *obj __UNUSED__,
254              void            *event_info)
255 {
256    Elm_Genlist_Item *it = event_info;
257    const char *path = elm_genlist_item_data_get(it);
258    _populate(data, path, it);
259 }
260
261 static void
262 _contract_done(void *data       __UNUSED__,
263                Evas_Object *obj __UNUSED__,
264                void            *event_info)
265 {
266    Elm_Genlist_Item *it = event_info;
267    elm_genlist_item_subitems_clear(it);
268 }
269
270 static void
271 _expand_req(void *data       __UNUSED__,
272             Evas_Object *obj __UNUSED__,
273             void            *event_info)
274 {
275    Elm_Genlist_Item *it = event_info;
276    elm_genlist_item_expanded_set(it, 1);
277 }
278
279 static void
280 _contract_req(void *data       __UNUSED__,
281               Evas_Object *obj __UNUSED__,
282               void            *event_info)
283 {
284    Elm_Genlist_Item *it = event_info;
285    elm_genlist_item_expanded_set(it, 0);
286 }
287
288 /***  PRIVATES  ***/
289 static Eina_Bool
290 _sel_do(void *data)
291 {
292    struct sel_data *sd;
293    const char *path;
294    Widget_Data *wd;
295    const char *p;
296
297    sd = data;
298    wd = elm_widget_data_get(sd->fs);
299    path = sd->path;
300
301    if ((!wd->only_folder) && ecore_file_is_dir(path))
302      {
303         if (wd->expand && wd->mode == ELM_FILESELECTOR_LIST)
304           {
305              _do_anchors(sd->fs, path);
306              elm_scrolled_entry_entry_set(wd->filename_entry, "");
307           }
308         else
309           {
310              /* keep a ref to path 'couse it will be destroyed by _populate */
311              p = eina_stringshare_add(path);
312              _populate(sd->fs, p, NULL);
313              eina_stringshare_del(p);
314           }
315         goto end;
316      }
317    else /* navigating through folders only or file is not a dir. */
318      {
319         if (wd->expand && wd->mode == ELM_FILESELECTOR_LIST)
320           _do_anchors(sd->fs, path);
321         else if (wd->only_folder)
322           {
323              /* keep a ref to path 'couse it will be destroyed by _populate */
324              p = eina_stringshare_add(path);
325              _populate(sd->fs, p, NULL);
326              eina_stringshare_del(p);
327           }
328         elm_scrolled_entry_entry_set(wd->filename_entry,
329                                      ecore_file_file_get(path));
330      }
331
332    evas_object_smart_callback_call(sd->fs, SIG_SELECTED, (void *)path);
333
334 end:
335    wd->sel_idler = NULL;
336    free(sd);
337    return ECORE_CALLBACK_CANCEL;
338 }
339
340 static void
341 _sel(void            *data,
342      Evas_Object *obj __UNUSED__,
343      void            *event_info)
344 {
345    struct sel_data *sd;
346    Widget_Data *wd;
347    void *old_sd;
348    char *dir;
349
350    wd = elm_widget_data_get(data);
351    if (!wd) return;
352
353    sd = malloc(sizeof(*sd));
354    sd->fs = data;
355    sd->path = wd->mode == ELM_FILESELECTOR_LIST ?
356        elm_genlist_item_data_get(event_info) :
357        elm_gengrid_item_data_get(event_info);
358
359    if (!sd->path)
360      {
361         eina_stringshare_replace(&wd->path, "");
362         goto end;
363      }
364
365    dir = wd->only_folder ? strdup(sd->path) : ecore_file_dir_get(sd->path);
366    if (dir)
367      {
368         eina_stringshare_replace(&wd->path, dir);
369         free(dir);
370      }
371    else
372      {
373         eina_stringshare_replace(&wd->path, "");
374      }
375
376 end:
377    if (wd->sel_idler)
378      {
379         old_sd = ecore_idler_del(wd->sel_idler);
380         free(old_sd);
381      }
382    wd->sel_idler = ecore_idler_add(_sel_do, sd);
383 }
384
385 static void
386 _up(void            *data,
387     Evas_Object *obj __UNUSED__,
388     void *event_info __UNUSED__)
389 {
390    Evas_Object *fs = data;
391    char *parent;
392
393    Widget_Data *wd = elm_widget_data_get(fs);
394    if (!wd) return;
395    parent = ecore_file_dir_get(wd->path);
396    _populate(fs, parent, NULL);
397    free(parent);
398 }
399
400 static void
401 _home(void            *data,
402       Evas_Object *obj __UNUSED__,
403       void *event_info __UNUSED__)
404 {
405    Evas_Object *fs = data;
406    _populate(fs, getenv("HOME"), NULL);
407 }
408
409 static void
410 _ok(void            *data,
411     Evas_Object *obj __UNUSED__,
412     void *event_info __UNUSED__)
413 {
414    Evas_Object *fs = data;
415    evas_object_smart_callback_call(fs, SIG_DONE,
416                                    (void *)elm_fileselector_selected_get(fs));
417 }
418
419 static void
420 _canc(void            *data,
421       Evas_Object *obj __UNUSED__,
422       void *event_info __UNUSED__)
423 {
424    Evas_Object *fs = data;
425    evas_object_smart_callback_call(fs, SIG_DONE, NULL);
426 }
427
428 static void
429 _anchor_clicked(void            *data,
430                 Evas_Object *obj __UNUSED__,
431                 void            *event_info)
432 {
433    Evas_Object *fs = data;
434    Widget_Data *wd = elm_widget_data_get(fs);
435    Elm_Entry_Anchor_Info *info = event_info;
436    const char *p;
437    if (!wd) return;
438    // keep a ref to path 'couse it will be destroyed by _populate
439    p = eina_stringshare_add(info->name);
440    _populate(fs, p, NULL);
441    evas_object_smart_callback_call(data, SIG_SELECTED, (void *)p);
442    eina_stringshare_del(p);
443 }
444
445 static void
446 _do_anchors(Evas_Object *obj,
447             const char  *path)
448 {
449    Widget_Data *wd = elm_widget_data_get(obj);
450    char **tok, buf[PATH_MAX * 3];
451    int i, j;
452    if (!wd) return;
453    buf[0] = '\0';
454    tok = eina_str_split(path, "/", 0);
455    eina_strlcat(buf, "<a href=/>root</a>", sizeof(buf));
456    for (i = 0; tok[i]; i++)
457      {
458         if ((!tok[i]) || (!tok[i][0])) continue;
459         eina_strlcat(buf, wd->path_separator, sizeof(buf));
460         eina_strlcat(buf, "<a href=", sizeof(buf));
461         for (j = 0; j <= i; j++)
462           {
463              if (strlen(tok[j]) < 1) continue;
464              eina_strlcat(buf, "/", sizeof(buf));
465              eina_strlcat(buf, tok[j], sizeof(buf));
466           }
467         eina_strlcat(buf, ">", sizeof(buf));
468         eina_strlcat(buf, tok[i], sizeof(buf));
469         eina_strlcat(buf, "</a>", sizeof(buf));
470      }
471    free(tok[0]);
472    free(tok);
473
474    elm_scrolled_entry_entry_set(wd->path_entry, buf);
475 }
476
477 static void
478 _populate(Evas_Object      *obj,
479           const char       *path,
480           Elm_Genlist_Item *parent)
481 {
482    Widget_Data *wd = elm_widget_data_get(obj);
483    DIR *dir;
484    struct dirent *dp;
485    char buf[PATH_MAX];
486    char *real;
487    Eina_List *files = NULL, *dirs = NULL, *l;
488
489    if ((!wd) || (!ecore_file_is_dir(path))) return;
490    dir = opendir(path);
491    if (!dir) return;
492    evas_object_smart_callback_call(obj, SIG_DIRECTORY_OPEN, (void *)path);
493    if (!parent)
494      {
495         elm_genlist_clear(wd->files_list);
496         elm_gengrid_clear(wd->files_grid);
497         eina_stringshare_replace(&wd->path, path);
498         _do_anchors(obj, path);
499      }
500
501    if (wd->filename_entry) elm_scrolled_entry_entry_set(wd->filename_entry, "");
502    while ((dp = readdir(dir)))
503      {
504         if (dp->d_name[0] == '.') continue;  // TODO make this configurable
505
506         snprintf(buf, sizeof(buf), "%s/%s", path, dp->d_name);
507         real = ecore_file_realpath(buf); /* TODO: this will resolv
508                                           * symlinks...I dont like
509                                           * it*/
510         if (ecore_file_is_dir(real))
511           dirs = eina_list_append(dirs, real);
512         else if (!wd->only_folder)
513           files = eina_list_append(files, real);
514      }
515    closedir(dir);
516
517    files = eina_list_sort(files, eina_list_count(files),
518                           EINA_COMPARE_CB(strcoll));
519    dirs = eina_list_sort(dirs, eina_list_count(dirs), EINA_COMPARE_CB(strcoll));
520    EINA_LIST_FOREACH(dirs, l, real)
521      {
522         if (wd->mode == ELM_FILESELECTOR_LIST)
523           elm_genlist_item_append(wd->files_list, &list_itc,
524                                   eina_stringshare_add(real), /* item data */
525                                   parent,
526                                   wd->expand ? ELM_GENLIST_ITEM_SUBITEMS :
527                                   ELM_GENLIST_ITEM_NONE,
528                                   NULL, NULL);
529         else if (wd->mode == ELM_FILESELECTOR_GRID)
530           elm_gengrid_item_append(wd->files_grid, &grid_itc,
531                                   eina_stringshare_add(real), /* item data */
532                                   NULL, NULL);
533
534         free(real);
535      }
536    eina_list_free(dirs);
537
538    EINA_LIST_FOREACH(files, l, real)
539      {
540         if (wd->mode == ELM_FILESELECTOR_LIST)
541           elm_genlist_item_append(wd->files_list, &list_itc,
542                                   eina_stringshare_add(real), /* item data */
543                                   parent, ELM_GENLIST_ITEM_NONE,
544                                   NULL, NULL);
545         else if (wd->mode == ELM_FILESELECTOR_GRID)
546           elm_gengrid_item_append(wd->files_grid, &grid_itc,
547                                   eina_stringshare_add(real), /* item data */
548                                   NULL, NULL);
549         free(real);
550      }
551    eina_list_free(files);
552 }
553
554 /***  API  ***/
555
556 /**
557  * Add a new Fileselector object
558  *
559  * @param parent The parent object
560  * @return The new object or NULL if it cannot be created
561  *
562  * @ingroup Fileselector
563  */
564 EAPI Evas_Object *
565 elm_fileselector_add(Evas_Object *parent)
566 {
567    Evas *e;
568    Evas_Object *obj, *ic, *bt, *li, *en, *grid;
569    Widget_Data *wd;
570    int s;
571
572    ELM_WIDGET_STANDARD_SETUP(wd, Widget_Data, parent, e, obj, NULL);
573
574    ELM_SET_WIDTYPE(widtype, "fileselector");
575    elm_widget_type_set(obj, "fileselector");
576    elm_widget_sub_object_add(parent, obj);
577    elm_widget_data_set(obj, wd);
578    elm_widget_del_hook_set(obj, _del_hook);
579    elm_widget_theme_hook_set(obj, _theme_hook);
580    elm_widget_can_focus_set(obj, EINA_FALSE);
581
582    wd->expand = !!_elm_config->fileselector_expand_enable;
583
584    wd->edje = edje_object_add(e);
585    _elm_theme_object_set(obj, wd->edje, "fileselector", "base", "default");
586    elm_widget_resize_object_set(obj, wd->edje);
587
588    // up btn
589    ic = elm_icon_add(parent);
590    elm_icon_standard_set(ic, "arrow_up");
591    evas_object_size_hint_aspect_set(ic, EVAS_ASPECT_CONTROL_VERTICAL, 1, 1);
592    bt = elm_button_add(parent);
593    elm_widget_mirrored_automatic_set(bt, EINA_FALSE);
594    elm_button_icon_set(bt, ic);
595    elm_button_label_set(bt, E_("Up"));
596    evas_object_size_hint_align_set(bt, 0.0, 0.0);
597
598    evas_object_smart_callback_add(bt, "clicked", _up, obj);
599
600    elm_widget_sub_object_add(obj, bt);
601    wd->up_button = bt;
602
603    // home btn
604    ic = elm_icon_add(parent);
605    elm_icon_standard_set(ic, "home");
606    evas_object_size_hint_aspect_set(ic, EVAS_ASPECT_CONTROL_VERTICAL, 1, 1);
607    bt = elm_button_add(parent);
608    elm_widget_mirrored_automatic_set(bt, EINA_FALSE);
609    elm_button_icon_set(bt, ic);
610    elm_button_label_set(bt, E_("Home"));
611    evas_object_size_hint_align_set(bt, 0.0, 0.0);
612
613    evas_object_smart_callback_add(bt, "clicked", _home, obj);
614
615    elm_widget_sub_object_add(obj, bt);
616    wd->home_button = bt;
617
618    list_itc.item_style = grid_itc.item_style = "default";
619    list_itc.func.label_get = grid_itc.func.label_get = _itc_label_get;
620    list_itc.func.icon_get = grid_itc.func.icon_get = _itc_icon_get;
621    list_itc.func.state_get = grid_itc.func.state_get = _itc_state_get;
622    list_itc.func.del = grid_itc.func.del = _itc_del;
623
624    li = elm_genlist_add(parent);
625    elm_widget_mirrored_automatic_set(li, EINA_FALSE);
626    evas_object_size_hint_align_set(li, EVAS_HINT_FILL, EVAS_HINT_FILL);
627    evas_object_size_hint_weight_set(li, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
628    evas_object_size_hint_min_set(li, 100, 100);
629
630    grid = elm_gengrid_add(parent);
631    elm_widget_mirrored_automatic_set(grid, EINA_FALSE);
632    evas_object_size_hint_align_set(grid, EVAS_HINT_FILL, EVAS_HINT_FILL);
633    evas_object_size_hint_weight_set(grid, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
634
635    s = elm_finger_size_get() * 2;
636    elm_gengrid_item_size_set(grid, s, s);
637    elm_gengrid_align_set(grid, 0.0, 0.0);
638
639    evas_object_smart_callback_add(li, "selected", _sel, obj);
640    evas_object_smart_callback_add(li, "expand,request", _expand_req, obj);
641    evas_object_smart_callback_add(li, "contract,request", _contract_req, obj);
642    evas_object_smart_callback_add(li, "expanded", _expand_done, obj);
643    evas_object_smart_callback_add(li, "contracted", _contract_done, obj);
644
645    evas_object_smart_callback_add(grid, "selected", _sel, obj);
646
647    elm_widget_sub_object_add(obj, li);
648    elm_widget_sub_object_add(obj, grid);
649    wd->files_list = li;
650    wd->files_grid = grid;
651
652    // path entry
653    en = elm_scrolled_entry_add(parent);
654    elm_widget_mirrored_automatic_set(en, EINA_FALSE);
655    elm_scrolled_entry_editable_set(en, EINA_FALSE);
656    elm_scrolled_entry_single_line_set(en, EINA_TRUE);
657    elm_scrolled_entry_line_char_wrap_set(en, EINA_TRUE);
658    evas_object_size_hint_weight_set(en, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
659    evas_object_size_hint_align_set(en, EVAS_HINT_FILL, EVAS_HINT_FILL);
660
661    evas_object_smart_callback_add(en, "anchor,clicked", _anchor_clicked, obj);
662
663    elm_widget_sub_object_add(obj, en);
664    wd->path_entry = en;
665
666    // filename entry
667    en = elm_scrolled_entry_add(parent);
668    elm_widget_mirrored_automatic_set(en, EINA_FALSE);
669    elm_scrolled_entry_editable_set(en, EINA_TRUE);
670    elm_scrolled_entry_single_line_set(en, EINA_TRUE);
671    elm_scrolled_entry_line_char_wrap_set(en, EINA_TRUE);
672    evas_object_size_hint_weight_set(en, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
673    evas_object_size_hint_align_set(en, EVAS_HINT_FILL, EVAS_HINT_FILL);
674
675    elm_widget_sub_object_add(obj, en);
676    wd->filename_entry = en;
677
678    elm_fileselector_buttons_ok_cancel_set(obj, EINA_TRUE);
679    elm_fileselector_is_save_set(obj, EINA_FALSE);
680
681    _theme_hook(obj);
682
683    evas_object_smart_callbacks_descriptions_set(obj, _signals);
684    return obj;
685 }
686
687 /**
688  * This enables/disables the file name entry box where the user can
689  * type in a name for the file to be saved as.
690  *
691  * @param obj The fileselector object
692  * @param is_save If true, the fileselector is a save dialog
693  *
694  * @ingroup Fileselector
695  */
696 EAPI void
697 elm_fileselector_is_save_set(Evas_Object *obj,
698                              Eina_Bool    is_save)
699 {
700    ELM_CHECK_WIDTYPE(obj, widtype);
701    Widget_Data *wd = elm_widget_data_get(obj);
702    if (!wd) return;
703
704    elm_object_disabled_set(wd->filename_entry, !is_save);
705
706    if (is_save)
707      edje_object_signal_emit(wd->edje, "elm,state,save,on", "elm");
708    else
709      edje_object_signal_emit(wd->edje, "elm,state,save,off", "elm");
710 }
711
712 /**
713  * This returns whether the fileselector is a "save" type fileselector
714  *
715  * @param obj The fileselector object
716  * @return If true, the fileselector is a save type.
717  *
718  * @ingroup Fileselector
719  */
720 EAPI Eina_Bool
721 elm_fileselector_is_save_get(const Evas_Object *obj)
722 {
723    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
724    Widget_Data *wd = elm_widget_data_get(obj);
725    if (!wd) return EINA_FALSE;
726    return elm_object_disabled_get(wd->filename_entry);
727 }
728
729 /**
730  * This enables/disables folder-only view in the fileselector.
731  *
732  * @param obj The fileselector object
733  * @param only If true, the fileselector will only display directories.
734  * If false, files are displayed also.
735  *
736  * @ingroup Fileselector
737  */
738 EAPI void
739 elm_fileselector_folder_only_set(Evas_Object *obj,
740                                  Eina_Bool    only)
741 {
742    ELM_CHECK_WIDTYPE(obj, widtype);
743    Widget_Data *wd = elm_widget_data_get(obj);
744    if (!wd) return;
745    if (wd->only_folder == only) return;
746    wd->only_folder = !!only;
747    if (wd->path) _populate(obj, wd->path, NULL);
748 }
749
750 /**
751  * This gets the state of file display in the fileselector.
752  *
753  * @param obj The fileselector object
754  * @return If true, files are not being shown in the fileselector.
755  * If false, files are being shown.
756  *
757  * @ingroup Fileselector
758  */
759 EAPI Eina_Bool
760 elm_fileselector_folder_only_get(const Evas_Object *obj)
761 {
762    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
763    Widget_Data *wd = elm_widget_data_get(obj);
764    if (!wd) return EINA_FALSE;
765    return wd->only_folder;
766 }
767
768 /**
769  * This enables/disables the ok,cancel buttons.
770  *
771  * @param obj The fileselector object
772  * @param only If true, a box containing ok and cancel buttons is created.
773  * If false, the box and the buttons are destroyed.
774  *
775  * @ingroup Fileselector
776  */
777 EAPI void
778 elm_fileselector_buttons_ok_cancel_set(Evas_Object *obj,
779                                        Eina_Bool    visible)
780 {
781    ELM_CHECK_WIDTYPE(obj, widtype);
782    Widget_Data *wd = elm_widget_data_get(obj);
783    Evas_Object *bt;
784    if (!wd) return;
785
786    if (visible)
787      {
788         // cancel btn
789         bt = elm_button_add(obj);
790         elm_widget_mirrored_automatic_set(bt, EINA_FALSE);
791         elm_button_label_set(bt, E_("Cancel"));
792
793         evas_object_smart_callback_add(bt, "clicked", _canc, obj);
794
795         elm_widget_sub_object_add(obj, bt);
796         wd->cancel_button = bt;
797
798         // ok btn
799         bt = elm_button_add(obj);
800         elm_widget_mirrored_automatic_set(bt, EINA_FALSE);
801         elm_button_label_set(bt, E_("OK"));
802
803         evas_object_smart_callback_add(bt, "clicked", _ok, obj);
804
805         elm_widget_sub_object_add(obj, bt);
806         wd->ok_button = bt;
807
808         _theme_hook(obj);
809      }
810    else
811      {
812         evas_object_del(wd->cancel_button);
813         wd->cancel_button = NULL;
814         evas_object_del(wd->ok_button);
815         wd->ok_button = NULL;
816      }
817 }
818
819 /**
820  * This gets the state of the box containing ok and cancel buttons.
821  *
822  * @param obj The fileselector object
823  * @return If true, the box exists.
824  * If false, the box does not exist.
825  *
826  * @ingroup Fileselector
827  */
828 EAPI Eina_Bool
829 elm_fileselector_buttons_ok_cancel_get(const Evas_Object *obj)
830 {
831    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
832    Widget_Data *wd = elm_widget_data_get(obj);
833    if (!wd) return EINA_FALSE;
834    return wd->ok_button ? EINA_TRUE : EINA_FALSE;
835 }
836
837 /**
838  * This enables a tree view in the fileselector, <b>if in @c
839  * ELM_FILESELECTOR_LIST mode</b>. If it's in other mode, the changes
840  * made by this function will only be visible when one switches back
841  * to list mode.
842  *
843  * @param obj The fileselector object
844  * @param expand If true, tree view is enabled.
845  * If false, tree view is disabled.
846  *
847  * In a tree view, arrows are created on the sides of directories,
848  * allowing them to expand in place.
849  *
850  * @ingroup Fileselector
851  */
852 EAPI void
853 elm_fileselector_expandable_set(Evas_Object *obj,
854                                 Eina_Bool    expand)
855 {
856    ELM_CHECK_WIDTYPE(obj, widtype);
857    Widget_Data *wd;
858
859    wd = elm_widget_data_get(obj);
860    if (!wd) return;
861
862    wd->expand = !!expand;
863
864    if (wd->path) _populate(obj, wd->path, NULL);
865 }
866
867 /**
868  * This gets the state of tree view in the fileselector.
869  *
870  * @param obj The fileselector object
871  * @return If true, tree view is enabled and folders will be expandable.
872  * If false, tree view is disabled.
873  *
874  * @ingroup Fileselector
875  */
876 EAPI Eina_Bool
877 elm_fileselector_expandable_get(const Evas_Object *obj)
878 {
879    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
880    Widget_Data *wd = elm_widget_data_get(obj);
881    if (!wd) return EINA_FALSE;
882    return wd->expand;
883 }
884
885 /**
886  * This sets the path that the fileselector will display.
887  *
888  * @param obj The fileselector object
889  * @param path The path of the fileselector
890  *
891  * @ingroup Fileselector
892  */
893 EAPI void
894 elm_fileselector_path_set(Evas_Object *obj,
895                           const char  *path)
896 {
897    ELM_CHECK_WIDTYPE(obj, widtype);
898    _populate(obj, path, NULL);
899 }
900
901 /**
902  * This gets the path that the fileselector displays.
903  *
904  * @param obj The fileselector object
905  * @return The path that the fileselector is displaying
906  *
907  * @ingroup Fileselector
908  */
909 EAPI const char *
910 elm_fileselector_path_get(const Evas_Object *obj)
911 {
912    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
913    Widget_Data *wd = elm_widget_data_get(obj);
914    if (!wd) return NULL;
915    return wd->path;
916 }
917
918 /**
919  * This sets the mode in which the fileselector will display files.
920  *
921  * @param obj The fileselector object
922
923  * @param mode The mode of the fileselector, being it one of @c
924  * ELM_FILESELECTOR_LIST (default) or @c ELM_FILESELECTOR_GRID. The
925  * first one, naturally, will display the files in a list. By using
926  * elm_fileselector_expandable_set(), the user will trigger a tree
927  * view for that list. The latter will make the widget to display its
928  * entries in a grid form.
929  *
930  * @see elm_fileselector_expandable_set().
931  *
932  * @ingroup Fileselector
933  */
934 EAPI void
935 elm_fileselector_mode_set(Evas_Object          *obj,
936                           Elm_Fileselector_Mode mode)
937 {
938    ELM_CHECK_WIDTYPE(obj, widtype);
939
940    Widget_Data *wd = elm_widget_data_get(obj);
941    if (!wd) return;
942
943    if (mode == wd->mode) return;
944
945    if (mode == ELM_FILESELECTOR_LIST)
946      {
947         if (edje_object_part_swallow(wd->edje, "elm.swallow.files",
948                                      wd->files_list))
949           {
950              evas_object_show(wd->files_list);
951              evas_object_hide(wd->files_grid);
952           }
953         else
954           evas_object_hide(wd->files_list);
955      }
956    else
957      {
958         if (edje_object_part_swallow(wd->edje, "elm.swallow.files",
959                                      wd->files_grid))
960           {
961              evas_object_show(wd->files_grid);
962              evas_object_hide(wd->files_list);
963           }
964         else
965           evas_object_hide(wd->files_grid);
966      }
967
968    wd->mode = mode;
969
970    _populate(obj, wd->path, NULL);
971 }
972
973 /**
974  * This gets the mode in which the fileselector is displaying files.
975  *
976  * @param obj The fileselector object
977  * @return The mode in which the fileselector is at
978  *
979  * @ingroup Fileselector
980  */
981 EAPI Elm_Fileselector_Mode
982 elm_fileselector_mode_get(const Evas_Object *obj)
983 {
984    ELM_CHECK_WIDTYPE(obj, widtype) ELM_FILESELECTOR_LAST;
985
986    Widget_Data *wd = elm_widget_data_get(obj);
987    if (!wd) return ELM_FILESELECTOR_LAST;
988
989    return wd->mode;
990 }
991
992 /**
993  * This gets the currently selected path in the file selector.
994  *
995  * @param obj The file selector object
996  * @return The absolute path of the selected object in the fileselector
997  *
998  * @ingroup Fileselector
999  */
1000 EAPI const char *
1001 elm_fileselector_selected_get(const Evas_Object *obj)
1002 {
1003    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
1004    Widget_Data *wd = elm_widget_data_get(obj);
1005    if (!wd) return NULL;
1006
1007    if (wd->filename_entry)
1008      {
1009         const char *name;
1010         char buf[PATH_MAX];
1011
1012         name = elm_scrolled_entry_entry_get(wd->filename_entry);
1013         snprintf(buf, sizeof(buf), "%s/%s",
1014                  wd->only_folder ? ecore_file_dir_get(wd->path) : wd->path,
1015                  name);
1016         eina_stringshare_replace(&wd->selection, buf);
1017         return wd->selection;
1018      }
1019
1020    if (wd->mode == ELM_FILESELECTOR_LIST)
1021      {
1022         Elm_Genlist_Item *it;
1023         it = elm_genlist_selected_item_get(wd->files_list);
1024         if (it) return elm_genlist_item_data_get(it);
1025      }
1026    else
1027      {
1028         Elm_Gengrid_Item *it;
1029         it = elm_gengrid_selected_item_get(wd->files_grid);
1030         if (it) return elm_gengrid_item_data_get(it);
1031      }
1032
1033    return wd->path;
1034 }
1035
1036 /**
1037  * This sets the currently selected path in the file selector.
1038  *
1039  * @param obj The file selector object
1040  * @param path The path to a file or directory
1041  * @return @c EINA_TRUE on success, @c EINA_FALSE on failure. The
1042  * latter case occurs if the directory or file pointed to do not
1043  * exist.
1044  *
1045  * @ingroup Fileselector
1046  */
1047 EAPI Eina_Bool
1048 elm_fileselector_selected_set(Evas_Object *obj,
1049                               const char  *path)
1050 {
1051    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
1052    Widget_Data *wd = elm_widget_data_get(obj);
1053    if (!wd) return EINA_FALSE;
1054
1055    if (ecore_file_is_dir(path))
1056      _populate(obj, path, NULL);
1057    else
1058      {
1059         if (!ecore_file_exists(path))
1060           return EINA_FALSE;
1061
1062         _populate(obj, ecore_file_dir_get(path), NULL);
1063         if (wd->filename_entry)
1064           {
1065              elm_scrolled_entry_entry_set(wd->filename_entry,
1066                                           ecore_file_file_get(path));
1067              eina_stringshare_replace(&wd->selection, path);
1068           }
1069      }
1070
1071    return EINA_TRUE;
1072 }
1073