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