105287d8bb15405b5c73e5faafd1fac2df260731
[framework/uifw/elementary.git] / src / lib / elc_fileselector.c
1 /**
2  * @defgroup Fileselector Fileselector
3  * @ingroup Elementary
4  *
5  * A fileselector is a widget that allows a user to navigate through a tree
6  * of files.  It contains buttons for Home(~) and Up(..) as well as cancel/ok
7  * buttons to confirm/cancel a selection.  This widget is currently very much
8  * in progress.
9  
10  * Signals that you can add callbacks for are:
11  *
12  * "selected" - the user clicks on a file
13  * "directory,open" - the list is populated with a new content. event_info is a directory.
14  * "done" - the user clicks on the ok or cancel button
15  */
16
17 #include <Elementary.h>
18 #include "elm_priv.h"
19
20 typedef struct _Widget_Data Widget_Data;
21
22 struct _Widget_Data
23 {
24    Evas_Object *vbox, *entry, *entry2, *list, *scr2;
25    const char *path;
26    const char *selection;
27    Eina_Bool only_folder;
28    Eina_Bool expand;
29    Ecore_Idler *sel_idler;
30
31    struct
32    {
33     Evas_Object *bx;
34     Evas_Object *ok;
35     Evas_Object *cancel;
36    } buttons;
37 };
38
39 struct sel_data
40 {
41    Evas_Object *fs;
42    const char *path;
43 };
44
45 Elm_Genlist_Item_Class itc;
46
47 static const char *widtype = NULL;
48
49 static const char SIG_DIRECTORY_OPEN[]= "directory,open";
50 static const char SIG_DONE[] = "done";
51 static const char SIG_SELECTED[] = "selected";
52 static const Evas_Smart_Cb_Description _signals[] = {
53   {SIG_DIRECTORY_OPEN, "s"},
54   {SIG_DONE, "s"},
55   {SIG_SELECTED, "s"},
56   {NULL, NULL}
57 };
58
59 static void _populate(Evas_Object *obj, const char *path, Elm_Genlist_Item *parent);
60 static void _do_anchors(Evas_Object *obj, const char *path);
61
62 /***  ELEMENTARY WIDGET  ***/
63 static void
64 _del_hook(Evas_Object *obj)
65 {
66    Widget_Data *wd;
67    void *sd;
68
69    wd = elm_widget_data_get(obj);
70    if (!wd) return;
71
72    if (wd->path) eina_stringshare_del(wd->path);
73    if (wd->selection) eina_stringshare_del(wd->selection);
74    if (wd->sel_idler)
75      {
76         sd = ecore_idler_del(wd->sel_idler);
77         free(sd);
78      }
79    free(wd);
80 }
81
82 static void
83 _sizing_eval(Evas_Object *obj)
84 {
85    Widget_Data *wd = elm_widget_data_get(obj);
86    Evas_Coord minw = -1, minh = -1;
87    if (!wd) return;
88    evas_object_size_hint_min_get(wd->vbox, &minw, &minh);
89    evas_object_size_hint_min_set(obj, minw, minh);
90 //   printf("***** SIZING EVAL [min %d %d] *************\n", minw, minh);
91 }
92
93 /***  GENLIST "MODEL"  ***/
94 static char*
95 _itc_label_get(const void *data, Evas_Object *obj __UNUSED__, const char *source __UNUSED__)
96 {
97    //~ printf("LABEL_GET: %s\n", (char*) data);
98    return strdup(ecore_file_file_get(data)); // NOTE this will be free() by the caller
99 }
100
101 static Evas_Object*
102 _itc_icon_get(const void *data, Evas_Object *obj, const char *source)
103 {
104    Evas_Object *ic;
105
106    //~ printf("ICON GET for %s (source: %s)\n", (char*)data, source);
107    if (!strcmp(source, "elm.swallow.icon"))
108      {
109         ic = elm_icon_add(obj);
110         if (ecore_file_is_dir((char*)data))
111           elm_icon_standard_set(ic, "folder");
112         else
113           elm_icon_standard_set(ic, "file");
114         evas_object_size_hint_aspect_set(ic, EVAS_ASPECT_CONTROL_VERTICAL, 1, 1);
115         evas_object_show(ic);
116         return ic;
117      }
118    return NULL;
119 }
120
121 static Eina_Bool
122 _itc_state_get(const void *data __UNUSED__, Evas_Object *obj __UNUSED__, const char *source __UNUSED__)
123 {
124    return EINA_FALSE;
125 }
126
127 static void
128 _itc_del(const void *data, Evas_Object *obj __UNUSED__)
129 {
130    //~ printf("DEL DATA [%s]\n", (char*)data);
131    eina_stringshare_del(data);
132 }
133
134 static void
135 _expand_done(void *data, Evas_Object *obj __UNUSED__, void *event_info)
136 {
137    Elm_Genlist_Item *it = event_info;
138    const char *path = elm_genlist_item_data_get(it);
139 //   printf("EXPAND %s\n", path);
140    _populate(data, path, it);
141 }
142
143 static void
144 _contract_done(void *data __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info)
145 {
146    Elm_Genlist_Item *it = event_info;
147 //   const char *path = elm_genlist_item_data_get(it);
148 //   printf("CONTRACT %s\n", path);
149    elm_genlist_item_subitems_clear(it);
150 }
151
152 static void
153 _expand_req(void *data __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info)
154 {
155    Elm_Genlist_Item *it = event_info;
156    elm_genlist_item_expanded_set(it, 1);
157 }
158
159 static void
160 _contract_req(void *data __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info)
161 {
162    Elm_Genlist_Item *it = event_info;
163    elm_genlist_item_expanded_set(it, 0);
164 }
165
166 /***  PRIVATES  ***/
167 static Eina_Bool
168 _sel_do(void *data)
169 {
170    struct sel_data *sd;
171    const char *path;
172    Widget_Data *wd;
173    const char *p;
174
175    sd = data;
176    wd = elm_widget_data_get(sd->fs);
177    path = sd->path;
178
179    if (ecore_file_is_dir(path))
180      {
181         //      printf("SELECTED DIR: %s\n", path);
182         if (wd->expand)
183           {
184              _do_anchors(sd->fs, path);
185              if (wd->entry2) elm_entry_entry_set(wd->entry2, "");
186           }
187         else
188           {
189              // keep a ref to path 'couse it will be destroyed by _populate
190              p = eina_stringshare_add(path);
191              _populate(sd->fs, p, NULL);
192              eina_stringshare_del(p);
193           }
194         goto end;
195      }
196    else
197      {
198         //      printf("SELECTED FILE: %s\n", path);
199         if (wd->entry2)
200           elm_entry_entry_set(wd->entry2, ecore_file_file_get(path));
201      }
202
203    evas_object_smart_callback_call(sd->fs, SIG_SELECTED, (void*)path);
204
205  end:
206    wd->sel_idler = NULL;
207    free(sd);
208    return ECORE_CALLBACK_CANCEL;
209 }
210
211 static void
212 _sel(void *data, Evas_Object *obj __UNUSED__, void *event_info)
213 {
214    struct sel_data *sd;
215    Widget_Data *wd;
216    void *old_sd;
217
218    wd = elm_widget_data_get(data);
219    if (!wd) return;
220
221    sd = malloc(sizeof(*sd));
222    sd->fs = data;
223    sd->path = elm_genlist_item_data_get(event_info);
224
225    if (wd->sel_idler)
226      {
227         old_sd = ecore_idler_del(wd->sel_idler);
228         free(old_sd);
229      }
230    wd->sel_idler = ecore_idler_add(_sel_do, sd);
231 }
232
233 static void
234 _up(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
235 {
236    Evas_Object *fs = data;
237    Widget_Data *wd = elm_widget_data_get(fs);
238    if (!wd) return;
239    char *parent = ecore_file_dir_get(wd->path);
240    _populate(fs, parent, NULL);
241    free(parent);
242 }
243
244 static void
245 _home(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
246 {
247    Evas_Object *fs = data;
248    _populate(fs, getenv("HOME"), NULL);
249 }
250
251 static void
252 _ok(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
253 {
254    Evas_Object *fs = data;
255    evas_object_smart_callback_call(fs, SIG_DONE,
256                                    (void*)elm_fileselector_selected_get(fs));
257 }
258
259 static void
260 _canc(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
261 {
262    Evas_Object *fs = data;
263    evas_object_smart_callback_call(fs, SIG_DONE, NULL);
264 }
265
266 static void
267 _anchor_clicked(void *data, Evas_Object *obj __UNUSED__, void *event_info)
268 {
269    Evas_Object *fs = data;
270    Widget_Data *wd = elm_widget_data_get(fs);
271    Elm_Entry_Anchor_Info *info = event_info;
272    const char *p;
273    if (!wd) return;
274    //~ printf("ANCHOR CLICKED %s\n", info->name);
275    // keep a ref to path 'couse it will be destroyed by _populate
276    p = eina_stringshare_add(info->name);
277    _populate(fs, p, NULL);
278    evas_object_smart_callback_call(data, SIG_SELECTED, (void*)p);
279    eina_stringshare_del(p);
280 }
281
282 static void
283 _do_anchors(Evas_Object *obj, const char *path)
284 {
285    Widget_Data *wd = elm_widget_data_get(obj);
286    char **tok, buf[PATH_MAX*3];
287    int i, j;
288    if (!wd) return;
289    //~ printf("ANCHORIZE...\n");
290    buf[0] = '\0';
291    tok = eina_str_split(path, "/", 0);
292    for (i = 0; tok[i]; i++)
293      {
294         if (strlen(tok[i]) < 1) continue;
295         //~ printf("TOK: %s\n", tok[i]);
296         eina_strlcat(buf, "/<a href=", sizeof(buf));
297         for (j = 0; j <= i; j++)
298           {
299              if (strlen(tok[j]) < 1) continue;
300              //~ printf("REV: %s\n",tok[j]);
301              eina_strlcat(buf, "/", sizeof(buf));
302              eina_strlcat(buf, tok[j], sizeof(buf));
303           }
304         eina_strlcat(buf, ">", sizeof(buf));
305         eina_strlcat(buf, tok[i], sizeof(buf));
306         eina_strlcat(buf, "</a>", sizeof(buf));
307      }
308    free(tok[0]);
309    free(tok);
310
311    //~ printf("ANCHOR: %s\n", buf);
312    elm_entry_entry_set(wd->entry, buf);
313 }
314
315 static void
316 _populate(Evas_Object *obj, const char *path, Elm_Genlist_Item *parent)
317 {
318    Widget_Data *wd = elm_widget_data_get(obj);
319    DIR *dir;
320    struct dirent *dp;
321    char buf[PATH_MAX];
322    char *real;
323    Eina_List *files = NULL, *dirs = NULL, *l;
324
325    if ((!wd) || (!ecore_file_is_dir(path))) return;
326    dir = opendir(path);
327    if (!dir) return;
328    evas_object_smart_callback_call(obj, SIG_DIRECTORY_OPEN, (void*)path);
329    if (!parent)
330      {
331         elm_genlist_clear(wd->list);
332         eina_stringshare_replace(&wd->path, path);
333         _do_anchors(obj, path);
334      }
335
336    if (wd->entry2) elm_entry_entry_set(wd->entry2, "");
337    while ((dp = readdir(dir)))
338      {
339         if (dp->d_name[0] == '.') continue; // TODO make this configurable
340
341         snprintf(buf, sizeof(buf), "%s/%s", path, dp->d_name);
342         real = ecore_file_realpath(buf); //TODO this will resolv symlinks...I dont like it
343         if (ecore_file_is_dir(real))
344           dirs = eina_list_append(dirs, real);
345         else if(!wd->only_folder)
346           files = eina_list_append(files, real);
347      }
348    closedir(dir);
349
350    files = eina_list_sort(files, eina_list_count(files), EINA_COMPARE_CB(strcoll));
351    dirs = eina_list_sort(dirs, eina_list_count(dirs), EINA_COMPARE_CB(strcoll));
352    EINA_LIST_FOREACH(dirs, l, real)
353      {
354         //~ printf("DIR: %s\n", real);
355         elm_genlist_item_append(wd->list, &itc,
356                                 eina_stringshare_add(real), /* item data */
357                                 parent,
358                                 wd->expand ? ELM_GENLIST_ITEM_SUBITEMS :
359                                 ELM_GENLIST_ITEM_NONE,
360                                 NULL, NULL);
361         free(real);
362      }
363    eina_list_free(dirs);
364
365    EINA_LIST_FOREACH(files, l, real)
366      {
367         //~ printf("FILE: %s [%p]\n", real, wd->list);
368         elm_genlist_item_append(wd->list, &itc,
369                                 eina_stringshare_add(real), /* item data */
370                                 parent, ELM_GENLIST_ITEM_NONE,
371                                 NULL, NULL);
372         free(real);
373      }
374    eina_list_free(files);
375 }
376
377 /***  API  ***/
378 /**
379  * Add a new Fileselector object
380  *
381  * @param parent The parent object
382  * @return The new object or NULL if it cannot be created
383  *
384  * @ingroup Fileselector
385  */
386 EAPI Evas_Object *
387 elm_fileselector_add(Evas_Object *parent)
388 {
389    Evas_Object *obj, *ic, *bt, *box;
390    Widget_Data *wd;
391
392    // Elementary Widget
393    wd = ELM_NEW(Widget_Data);
394    wd->expand = EINA_FALSE;
395    obj = elm_widget_add(evas_object_evas_get(parent));
396    ELM_SET_WIDTYPE(widtype, "fileselector");
397    elm_widget_type_set(obj, "fileselector");
398    elm_widget_sub_object_add(parent, obj);
399    elm_widget_data_set(obj, wd);
400    elm_widget_del_hook_set(obj, _del_hook);
401
402    // TODO Do we need a bg object? a frame?
403    // vbox
404    wd->vbox = elm_box_add(parent);
405    evas_object_size_hint_weight_set(wd->vbox, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
406    elm_widget_resize_object_set(obj, wd->vbox);
407    evas_object_show(wd->vbox);
408
409    // buttons box
410    box = elm_box_add(parent);
411    elm_box_horizontal_set(box, 1);
412    elm_widget_sub_object_add(obj, box);
413    elm_box_pack_end(wd->vbox, box);
414    evas_object_size_hint_align_set(box, 0.0, 0.0);
415    evas_object_show(box);
416
417    // up btn
418    ic = elm_icon_add(parent);
419    elm_icon_standard_set(ic, "arrow_up");
420    evas_object_size_hint_aspect_set(ic, EVAS_ASPECT_CONTROL_VERTICAL, 1, 1);
421    bt = elm_button_add(parent);
422    elm_button_icon_set(bt, ic);
423    elm_button_label_set(bt, "Up");
424    evas_object_size_hint_align_set(bt, 0.0, 0.0);
425    elm_widget_sub_object_add(obj, bt);
426    elm_box_pack_end(box, bt);
427    evas_object_smart_callback_add(bt, "clicked", _up, obj);
428    evas_object_show(bt);
429
430    // home btn
431    ic = elm_icon_add(parent);
432    elm_icon_standard_set(ic, "home");
433    evas_object_size_hint_aspect_set(ic, EVAS_ASPECT_CONTROL_VERTICAL, 1, 1);
434    bt = elm_button_add(parent);
435    elm_button_icon_set(bt, ic);
436    elm_button_label_set(bt, "Home");
437    evas_object_size_hint_align_set(bt, 0.0, 0.0);
438    elm_widget_sub_object_add(obj, bt);
439    elm_box_pack_end(box, bt);
440    evas_object_smart_callback_add(bt, "clicked", _home, obj);
441    evas_object_show(bt);
442
443    // genlist
444    itc.item_style = "default";
445    itc.func.label_get = _itc_label_get;
446    itc.func.icon_get = _itc_icon_get;
447    itc.func.state_get = _itc_state_get;
448    itc.func.del = _itc_del;
449
450    wd->list = elm_genlist_add(parent);
451    evas_object_size_hint_align_set(wd->list, EVAS_HINT_FILL, EVAS_HINT_FILL);
452    evas_object_size_hint_weight_set(wd->list, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
453    evas_object_size_hint_min_set(wd->list, 100, 100);
454    elm_widget_sub_object_add(obj, wd->list);
455    elm_box_pack_end(wd->vbox, wd->list);
456    evas_object_show(wd->list);
457
458    evas_object_smart_callback_add(wd->list, "selected", _sel, obj);
459    evas_object_smart_callback_add(wd->list, "expand,request", _expand_req, obj);
460    evas_object_smart_callback_add(wd->list, "contract,request", _contract_req, obj);
461    evas_object_smart_callback_add(wd->list, "expanded", _expand_done, obj);
462    evas_object_smart_callback_add(wd->list, "contracted", _contract_done, obj);
463
464    // path entry
465    wd->entry = elm_entry_add(parent);
466    elm_widget_sub_object_add(obj, wd->entry);
467    elm_entry_editable_set(wd->entry, 0);
468    elm_entry_single_line_set(wd->entry, EINA_FALSE);
469    elm_entry_line_char_wrap_set(wd->entry, EINA_TRUE);
470    evas_object_size_hint_weight_set(wd->entry, EVAS_HINT_EXPAND, 0.0);
471    evas_object_size_hint_align_set(wd->entry, EVAS_HINT_FILL, 0.0);
472    elm_box_pack_end(wd->vbox, wd->entry);
473    evas_object_show(wd->entry);
474    evas_object_smart_callback_add(wd->entry, "anchor,clicked", _anchor_clicked, obj);
475
476    // name entry scroller
477    wd->scr2 = elm_scroller_add(parent);
478    elm_scroller_content_min_limit(wd->scr2, 0, 1);
479    elm_scroller_policy_set(wd->scr2, ELM_SCROLLER_POLICY_OFF, ELM_SCROLLER_POLICY_OFF);
480    evas_object_size_hint_weight_set(wd->scr2, EVAS_HINT_EXPAND, 0.0);
481    evas_object_size_hint_align_set(wd->scr2, EVAS_HINT_FILL, EVAS_HINT_FILL);
482    elm_box_pack_end(wd->vbox, wd->scr2);
483    evas_object_show(wd->scr2);
484
485    elm_fileselector_buttons_ok_cancel_set(obj, 1);
486
487    // Is this the right way to show sub-objs ?? or use the show/hide cbs ??
488    //~ evas_object_event_callback_add(obj, EVAS_CALLBACK_SHOW, _show, obj);
489    //~ evas_object_event_callback_add(obj, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
490    //~ _changed_size_hints, obj);
491    _sizing_eval(obj);
492
493    // TODO: convert Elementary to subclassing of Evas_Smart_Class
494    // TODO: and save some bytes, making descriptions per-class and not instance!
495    evas_object_smart_callbacks_descriptions_set(obj, _signals);
496    return obj;
497 }
498
499 /**
500  * This enables/disables the file name entry box where the user can
501  * type in a name for the file to be saved as.
502  *
503  * @param obj The fileselector object
504  * @param is_save If true, the fileselector is a save dialog
505  *
506  * @ingroup Fileselector
507  */
508 EAPI void
509 elm_fileselector_is_save_set(Evas_Object *obj, Eina_Bool is_save)
510 {
511    ELM_CHECK_WIDTYPE(obj, widtype);
512    Widget_Data *wd = elm_widget_data_get(obj);
513    if (!wd) return;
514    if (is_save)
515      {
516         if (wd->entry2) return;
517         wd->entry2 = elm_entry_add(elm_widget_parent_get(obj));
518         elm_widget_sub_object_add(obj, wd->entry2);
519         elm_entry_editable_set(wd->entry2, 1);
520         elm_entry_single_line_set(wd->entry2, EINA_TRUE);
521         evas_object_size_hint_weight_set(wd->entry2, EVAS_HINT_EXPAND, 0.0);
522         evas_object_size_hint_align_set(wd->entry2, EVAS_HINT_FILL, 0.0);
523         elm_scroller_content_set(wd->scr2, wd->entry2);
524         evas_object_show(wd->entry2);
525      }
526    else
527      {
528         evas_object_del(wd->entry2);
529         wd->entry2 = NULL;
530      }
531 }
532
533 /**
534  * This returns whether the fileselector is a "save" type fileselector
535  *
536  * @param obj The fileselector object
537  * @return If true, the fileselector is a save type.
538  *
539  * @ingroup Fileselector
540  */
541 EAPI Eina_Bool
542 elm_fileselector_is_save_get(const Evas_Object *obj)
543 {
544    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
545    Widget_Data *wd = elm_widget_data_get(obj);
546    if (!wd) return EINA_FALSE;
547    return wd->entry2 ? EINA_TRUE : EINA_FALSE;
548 }
549
550
551 /**
552  * This enables/disables folder-only view in the fileselector.
553  *
554  * @param obj The fileselector object
555  * @param only If true, the fileselector will only display directories.
556  * If false, files are displayed also.
557  *
558  * @ingroup Fileselector
559  */
560 EAPI void
561 elm_fileselector_folder_only_set(Evas_Object *obj, Eina_Bool only)
562 {
563    ELM_CHECK_WIDTYPE(obj, widtype);
564    Widget_Data *wd = elm_widget_data_get(obj);
565    if (!wd) return;
566    if (wd->only_folder == only) return;
567    wd->only_folder = only;
568 }
569
570
571 /**
572  * This gets the state of file display in the fileselector.
573  *
574  * @param obj The fileselector object
575  * @return If true, files are not being shown in the fileselector.
576  * If false, files are being shown.
577  *
578  * @ingroup Fileselector
579  */
580 EAPI Eina_Bool
581 elm_fileselector_folder_only_get(const Evas_Object *obj)
582 {
583    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
584    Widget_Data *wd = elm_widget_data_get(obj);
585    if (!wd) return EINA_FALSE;
586    return wd->only_folder;
587 }
588
589
590 /**
591  * This enables/disables the file name entry box where the user can
592  * type in the name of a file to be selected.
593  *
594  * @param obj The fileselector object
595  * @param only If true, a box containing ok and cancel buttons is created.
596  * If false, the box and the buttons are destroyed.
597  *
598  * @ingroup Fileselector
599  */
600 EAPI void
601 elm_fileselector_buttons_ok_cancel_set(Evas_Object *obj, Eina_Bool only)
602 {
603    ELM_CHECK_WIDTYPE(obj, widtype);
604    Widget_Data *wd = elm_widget_data_get(obj);
605    Evas_Object *box, *bt;
606    if (!wd) return;
607    if (only)
608      {
609         if (wd->buttons.bx) return;
610         // buttons box
611         box = elm_box_add(obj);
612         wd->buttons.bx = box;
613         elm_box_horizontal_set(box, 1);
614         elm_widget_sub_object_add(obj, box);
615         elm_box_pack_end(wd->vbox, box);
616         evas_object_show(box);
617
618         // cancel btn
619         bt = elm_button_add(obj);
620         wd->buttons.cancel = bt;
621         elm_button_label_set(bt, "Cancel");
622         elm_widget_sub_object_add(obj, bt);
623         elm_box_pack_end(box, bt);
624         evas_object_smart_callback_add(bt, "clicked", _canc, obj);
625         evas_object_show(bt);
626
627         // ok btn
628         bt = elm_button_add(obj);
629         wd->buttons.ok = bt;
630         elm_button_label_set(bt, "OK");
631         elm_widget_sub_object_add(obj, bt);
632         elm_box_pack_end(box, bt);
633         evas_object_smart_callback_add(bt, "clicked", _ok, obj);
634         evas_object_show(bt);
635      }
636    else
637      {
638         evas_object_del(wd->buttons.bx);
639         evas_object_del(wd->buttons.ok);
640         evas_object_del(wd->buttons.cancel);
641         wd->buttons.bx = NULL;
642      }
643 }
644
645
646 /**
647  * This gets the state of the box containing ok and cancel buttons.
648  *
649  * @param obj The fileselector object
650  * @return If true, the box exists.
651  * If false, the box does not exist.
652  *
653  * @ingroup Fileselector
654  */
655 EAPI Eina_Bool
656 elm_fileselector_buttons_ok_cancel_get(const Evas_Object *obj)
657 {
658    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
659    Widget_Data *wd = elm_widget_data_get(obj);
660    if (!wd) return EINA_FALSE;
661    return wd->buttons.bx ? EINA_TRUE : EINA_FALSE;
662 }
663
664
665 /**
666  * This enables tree view in the fileselector.  Arrows are created on the
667  * sides of directories, allowing them to expand in place.
668  *
669  * @param obj The fileselector object
670  * @param expand If true, tree view is enabled.
671  * If false, tree view is disabled.
672  *
673  * @ingroup Fileselector
674  */
675 EAPI void
676 elm_fileselector_expandable_set(Evas_Object *obj, Eina_Bool expand)
677 {
678    ELM_CHECK_WIDTYPE(obj, widtype);
679    Widget_Data *wd;
680
681    wd = elm_widget_data_get(obj);
682    if (!wd) return;
683
684    wd->expand = expand;
685 }
686
687 /**
688  * This gets the state of tree view in the fileselector.
689  *
690  * @param obj The fileselector object
691  * @return If true, tree view is enabled and folders will be expandable.
692  * If false, tree view is disabled.
693  *
694  * @ingroup Fileselector
695  */
696 EAPI Eina_Bool
697 elm_fileselector_expandable_get(const Evas_Object *obj)
698 {
699    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
700    Widget_Data *wd = elm_widget_data_get(obj);
701    if (!wd) return EINA_FALSE;
702    return wd->expand;
703 }
704
705 /**
706  * This sets the path that the fileselector will display.
707  *
708  * @param obj The fileselector object
709  * @param path The path of the fileselector
710  *
711  * @ingroup Fileselector
712  */
713 EAPI void
714 elm_fileselector_path_set(Evas_Object *obj, const char *path)
715 {
716    _populate(obj, path, NULL);
717 }
718
719 /**
720  * This gets the path that the fileselector displays.
721  *
722  * @param obj The fileselector object
723  * @return The path that the fileselector is displaying
724  *
725  * @ingroup Fileselector
726  */
727 EAPI const char *
728 elm_fileselector_path_get(const Evas_Object *obj)
729 {
730    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
731    Widget_Data *wd = elm_widget_data_get(obj);
732    if (!wd) return NULL;
733    return wd->path;
734 }
735
736 /**
737  * This gets the currently selected path in the file selector.
738  *
739  * @param obj The file selector object
740  * @return The absolute path of the selected object in the fileselector
741  *
742  * @ingroup Fileselector
743  */
744 EAPI const char *
745 elm_fileselector_selected_get(const Evas_Object *obj)
746 {
747    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
748    Widget_Data *wd = elm_widget_data_get(obj);
749    Elm_Genlist_Item *it;
750    if (!wd) return NULL;
751    if (wd->entry2)
752      {
753         const char *name;
754         char buf[PATH_MAX];
755
756         name = elm_entry_entry_get(wd->entry2);
757         //TODO remove <br>
758         snprintf(buf, sizeof(buf), "%s/%s", wd->path, name);
759         eina_stringshare_replace(&wd->selection, buf);
760         return wd->selection;
761      }
762
763    it = elm_genlist_selected_item_get(wd->list);
764    if (it) return elm_genlist_item_data_get(it);
765
766    return wd->path;
767 }
768
769 /**
770  * This sets the currently selected path in the file selector.
771  *
772  * @param obj The file selector object
773  * @param path The path to a file or directory
774  * @return @c EINA_TRUE on success, @c EINA_FALSE on failure. The
775  * latter case occurs if the directory or file pointed to do not
776  * exist.
777  *
778  * @ingroup Fileselector
779  */
780 EAPI Eina_Bool
781 elm_fileselector_selected_set(Evas_Object *obj, const char *path)
782 {
783    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
784    Widget_Data *wd = elm_widget_data_get(obj);
785    if (!wd) return EINA_FALSE;
786
787    if (ecore_file_is_dir(path)) _populate(obj, path, NULL);
788    else
789      {
790         if (!ecore_file_exists(path)) return EINA_FALSE;
791
792         _populate(obj, ecore_file_dir_get(path), NULL);
793         if (wd->entry2)
794           {
795              elm_entry_entry_set(wd->entry2, ecore_file_file_get(path));
796              eina_stringshare_replace(&wd->selection, path);
797           }
798      }
799
800    return EINA_TRUE;
801 }