diff --git a/legacy/elementary/ChangeLog b/legacy/elementary/ChangeLog index f3f38d1bb7..a5d36f2080 100644 --- a/legacy/elementary/ChangeLog +++ b/legacy/elementary/ChangeLog @@ -1450,3 +1450,7 @@ 2013-06-23 ChunEon Park (Hermet) * Apply current ctxpopup style to the list in the ctxpopup. + +2013-06-24 Ryuan Choi (ryuan) + + * fileselector : Add support mime type filter diff --git a/legacy/elementary/NEWS b/legacy/elementary/NEWS index 50a252d5d5..8fb389f0ff 100644 --- a/legacy/elementary/NEWS +++ b/legacy/elementary/NEWS @@ -75,6 +75,7 @@ Additions: * Add magnifier to entry. * Add "focused" and "unfocused" smart callback for panel, video, web, web2, genlist, hover, index, list, map, photocam, progressbar, radio, scroller, slider, slideshow, spinner, toolbar, win, calendar, check, clock, colorselector, datetime, diskselector, flipselector, gengrid, ctxpopup, fileselector_button, naviframe, player, popup, bubble, button. * Add elm_web_url_set(), elm_web_url_get() and "url,changed" signal for web, web2. + * Add elm_fileselector_mime_type_filter_append and elm_fileselector_filters_clear to support mime type filter. Improvements: diff --git a/legacy/elementary/data/themes/widgets/fileselector.edc b/legacy/elementary/data/themes/widgets/fileselector.edc index ccd9e6ec27..f8d158cf93 100644 --- a/legacy/elementary/data/themes/widgets/fileselector.edc +++ b/legacy/elementary/data/themes/widgets/fileselector.edc @@ -110,10 +110,27 @@ group { name: "elm/fileselector/base/default"; align: 0.5 1.0; fixed: 1 1; rel1 { - to_y: "elm.swallow.ok"; + to_y: "elm.swallow.filters"; relative: 0.0 0.0; offset: 0 -1; } + rel2 { + to_y: "elm.swallow.filters"; + relative: 1.0 0.0; + offset: -1 -1; + } + } + } + part { name: "elm.swallow.filters"; + type: SWALLOW; + description { state: "default" 0.0; + align: 1.0 1.0; + fixed: 1 1; + rel1 { + to_y: "elm.swallow.ok"; + relative: 1.0 0.0; + offset: 0 -1; + } rel2 { to_y: "elm.swallow.ok"; relative: 1.0 0.0; diff --git a/legacy/elementary/src/bin/test_fileselector.c b/legacy/elementary/src/bin/test_fileselector.c index dd532ff511..dfa7f02ec8 100644 --- a/legacy/elementary/src/bin/test_fileselector.c +++ b/legacy/elementary/src/bin/test_fileselector.c @@ -141,6 +141,7 @@ test_fileselector(void *data __UNUSED__, setlocale(LC_ALL, ""); elm_need_ethumb(); + elm_need_efreet(); win = elm_win_util_standard_add("fileselector", "File Selector"); elm_win_autodel_set(win, EINA_TRUE); @@ -157,6 +158,9 @@ test_fileselector(void *data __UNUSED__, elm_fileselector_expandable_set(fs, EINA_FALSE); /* start the fileselector in the home dir */ elm_fileselector_path_set(fs, getenv("HOME")); + elm_fileselector_mime_types_filter_append(fs, "text/*", "Text Files"); + elm_fileselector_mime_types_filter_append(fs, "image/*", "Image Files"); + /* allow fs to expand in x & y */ evas_object_size_hint_weight_set(fs, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); evas_object_size_hint_align_set(fs, EVAS_HINT_FILL, EVAS_HINT_FILL); diff --git a/legacy/elementary/src/lib/elc_fileselector.c b/legacy/elementary/src/lib/elc_fileselector.c index 7aafda512f..c7742187cf 100644 --- a/legacy/elementary/src/lib/elc_fileselector.c +++ b/legacy/elementary/src/lib/elc_fileselector.c @@ -7,7 +7,8 @@ * - double click to choose a file * - multi-selection * - make variable/function names that are sensible - * - Filter support + * - Pattern Filter support + * - Custom Filter support */ #ifdef HAVE_CONFIG_H # include "elementary_config.h" @@ -127,6 +128,7 @@ _elm_fileselector_smart_theme(Eo *obj, void *_pd, va_list *list) SWALLOW("elm.swallow.path", sd->path_entry); snprintf(buf, sizeof(buf), "fileselector/actions/%s", style); + SWALLOW("elm.swallow.filters", sd->filter_hoversel); SWALLOW("elm.swallow.cancel", sd->cancel_button); SWALLOW("elm.swallow.ok", sd->ok_button); @@ -253,6 +255,50 @@ _anchors_do(Evas_Object *obj, elm_object_text_set(sd->path_entry, buf); } +static Eina_Bool +_mime_type_matched(const char *mime_filter, const char *mime_type) +{ + int i = 0; + + while (mime_filter[i] != '\0') + { + if (mime_filter[i] != mime_type[i]) + { + if (mime_filter[i] == '*' && mime_filter[i + 1] == '\0') + return EINA_TRUE; + + return EINA_FALSE; + } + i++; + } + + if (mime_type[i] != '\0') return EINA_FALSE; + + return EINA_TRUE; +} + +static Eina_Bool +_check_filters(const Elm_Fileselector_Filter *filter, const char *file_name) +{ + const char *mime_type = NULL; + int i; + + if (!filter) return EINA_TRUE; + +#ifdef ELM_EFREET + mime_type = efreet_mime_type_get(file_name); +#endif + + if (!mime_type) return EINA_FALSE; + + for (i = 0; filter->mime_types[i]; ++i) + { + if (_mime_type_matched(filter->mime_types[i], mime_type)) + return EINA_TRUE; + } + return EINA_FALSE; +} + #ifdef HAVE_EIO static Eina_Bool _ls_filter_cb(void *data, @@ -267,6 +313,9 @@ _ls_filter_cb(void *data, if (lreq->sd->only_folder && info->type != EINA_FILE_DIR) return EINA_FALSE; + if (info->type != EINA_FILE_DIR && !_check_filters(lreq->sd->current_filter, info->path)) + return EINA_FALSE; + return EINA_TRUE; } @@ -452,7 +501,7 @@ _populate(Evas_Object *obj, filename = eina_stringshare_add(file->path); if (file->type == EINA_FILE_DIR) dirs = eina_list_append(dirs, filename); - else if (!sd->only_folder) + else if (!sd->only_folder && _check_filters(sd->current_filter, filename)) files = eina_list_append(files, filename); } eina_iterator_free(it); @@ -673,6 +722,21 @@ _home(void *data, _populate(fs, getenv("HOME"), NULL); } +static void +_current_filer_changed(void *data, + Evas_Object *obj, + void *event_info __UNUSED__) +{ + Elm_Fileselector_Filter *filter = data; + + if (filter->sd->current_filter == filter) return; + + elm_object_text_set(obj, filter->filter_name); + filter->sd->current_filter = filter; + + _populate(filter->sd->obj, filter->sd->path, NULL); +} + static void _ok(void *data, Evas_Object *obj __UNUSED__, @@ -881,6 +945,7 @@ _elm_fileselector_smart_del(Eo *obj EINA_UNUSED, void *_pd, va_list *list EINA_U int i; Elm_Fileselector_Smart_Data *sd = _pd; + Elm_Fileselector_Filter *filter; for (i = 0; i < ELM_FILE_LAST; ++i) { @@ -892,6 +957,16 @@ _elm_fileselector_smart_del(Eo *obj EINA_UNUSED, void *_pd, va_list *list EINA_U if (sd->current) eio_file_cancel(sd->current); #endif + EINA_LIST_FREE(sd->filter_list, filter) + { + eina_stringshare_del(filter->filter_name); + + free(filter->mime_types[0]); + free(filter->mime_types); + + free(filter); + } + sd->files_list = NULL; sd->files_grid = NULL; @@ -1265,6 +1340,93 @@ clean_up: free(path); } +EAPI Eina_Bool +elm_fileselector_mime_types_filter_append(Evas_Object *obj, const char *mime_type, const char *filter_name) +{ + ELM_FILESELECTOR_CHECK(obj) EINA_FALSE; + Eina_Bool ret = EINA_FALSE; + eo_do(obj, elm_obj_fileselector_mime_types_filter_append(mime_type, filter_name, &ret)); + return ret; +} + +static void +_mime_types_filter_append(Eo *obj, void *_pd, va_list *list) +{ + const char *mime_types = va_arg(*list, const char *); + const char *filter_name = va_arg(*list, const char *); + Eina_Bool *ret = va_arg(*list, Eina_Bool *); + + Elm_Fileselector_Smart_Data *sd; + Elm_Fileselector_Filter *ff; + Eina_Bool int_ret = EINA_FALSE; + Eina_Bool need_theme = EINA_FALSE; + + if (!mime_types) goto end; + + sd = _pd; + + ff = malloc(sizeof(Elm_Fileselector_Filter)); + if (!ff) goto end; + + if (filter_name) + ff->filter_name = eina_stringshare_add(filter_name); + else + ff->filter_name = eina_stringshare_add(mime_types); + + ff->sd = sd; + + ff->mime_types = eina_str_split(mime_types, ",", 0); + + if (!sd->filter_list) + { + sd->current_filter = ff; + sd->filter_hoversel = elm_hoversel_add(obj); + elm_object_text_set(sd->filter_hoversel, ff->filter_name); + need_theme = EINA_TRUE; + } + elm_hoversel_item_add(sd->filter_hoversel, ff->filter_name, NULL, ELM_ICON_NONE, _current_filer_changed, ff); + + sd->filter_list = eina_list_append(sd->filter_list, ff); + + _populate(obj, sd->path, NULL); + + if (need_theme) + eo_do(obj, elm_wdg_theme(NULL)); + + int_ret = EINA_TRUE; + +end: + if (ret) *ret = int_ret; +} + +EAPI void +elm_fileselector_filters_clear(Evas_Object *obj) +{ + ELM_FILESELECTOR_CHECK(obj); + eo_do(obj, elm_obj_fileselector_filters_clear()); +} + +static void +_filters_clear(Eo *obj, void *_pd, va_list *list EINA_UNUSED) +{ + Elm_Fileselector_Smart_Data *sd = _pd; + Elm_Fileselector_Filter *filter; + + EINA_LIST_FREE(sd->filter_list, filter) + { + eina_stringshare_del(filter->filter_name); + + free(filter->mime_types[0]); + free(filter->mime_types); + + free(filter); + } + + ELM_SAFE_FREE(sd->filter_hoversel, evas_object_del); + + _populate(obj, sd->path, NULL); +} + static void _elm_fileselector_smart_focus_next_manager_is(Eo *obj EINA_UNUSED, void *_pd EINA_UNUSED, va_list *list) { @@ -1308,6 +1470,8 @@ _class_constructor(Eo_Class *klass) EO_OP_FUNC(ELM_OBJ_FILESELECTOR_ID(ELM_OBJ_FILESELECTOR_SUB_ID_MODE_GET), _mode_get), EO_OP_FUNC(ELM_OBJ_FILESELECTOR_ID(ELM_OBJ_FILESELECTOR_SUB_ID_SELECTED_GET), _selected_get), EO_OP_FUNC(ELM_OBJ_FILESELECTOR_ID(ELM_OBJ_FILESELECTOR_SUB_ID_SELECTED_SET), _selected_set), + EO_OP_FUNC(ELM_OBJ_FILESELECTOR_ID(ELM_OBJ_FILESELECTOR_SUB_ID_MIME_TYPES_FILTER_APPEND), _mime_types_filter_append), + EO_OP_FUNC(ELM_OBJ_FILESELECTOR_ID(ELM_OBJ_FILESELECTOR_SUB_ID_FILTERS_CLEAR), _filters_clear), EO_OP_FUNC_SENTINEL }; eo_class_funcs_set(klass, func_desc); @@ -1329,6 +1493,8 @@ static const Eo_Op_Description op_desc[] = { EO_OP_DESCRIPTION(ELM_OBJ_FILESELECTOR_SUB_ID_MODE_GET, "Get the mode in which a given file selector widget is displaying (layouting) file system entries in its view."), EO_OP_DESCRIPTION(ELM_OBJ_FILESELECTOR_SUB_ID_SELECTED_GET, "Get the currently selected item's (full) path, in the given file selector widget."), EO_OP_DESCRIPTION(ELM_OBJ_FILESELECTOR_SUB_ID_SELECTED_SET, "Set, programmatically, the currently selected file/directory in the given file selector widget."), + EO_OP_DESCRIPTION(ELM_OBJ_FILESELECTOR_SUB_ID_MIME_TYPES_FILTER_APPEND, "Append mime type filter"), + EO_OP_DESCRIPTION(ELM_OBJ_FILESELECTOR_SUB_ID_FILTERS_CLEAR, "Clear filters"), EO_OP_DESCRIPTION_SENTINEL }; static const Eo_Class_Description class_desc = { diff --git a/legacy/elementary/src/lib/elc_fileselector_eo.h b/legacy/elementary/src/lib/elc_fileselector_eo.h index 06eba98698..38485d1e57 100644 --- a/legacy/elementary/src/lib/elc_fileselector_eo.h +++ b/legacy/elementary/src/lib/elc_fileselector_eo.h @@ -25,6 +25,8 @@ enum ELM_OBJ_FILESELECTOR_SUB_ID_MODE_GET, ELM_OBJ_FILESELECTOR_SUB_ID_SELECTED_GET, ELM_OBJ_FILESELECTOR_SUB_ID_SELECTED_SET, + ELM_OBJ_FILESELECTOR_SUB_ID_MIME_TYPES_FILTER_APPEND, + ELM_OBJ_FILESELECTOR_SUB_ID_FILTERS_CLEAR, ELM_OBJ_FILESELECTOR_SUB_ID_LAST }; @@ -206,6 +208,32 @@ enum * @see elm_fileselector_selected_set */ #define elm_obj_fileselector_selected_set(_path, ret) ELM_OBJ_FILESELECTOR_ID(ELM_OBJ_FILESELECTOR_SUB_ID_SELECTED_SET), EO_TYPECHECK(const char *, _path), EO_TYPECHECK(Eina_Bool *, ret) + +/** + * @def elm_obj_fileselector_mime_type_filter_append + * @since 1.8 + * + * Append mime type based filter into filter list + * + * @param[in] mime_types + * @param[in] filter_name + * @param[out] ret + * + * @see elm_fileselector_mime_type_filter_append + */ +#define elm_obj_fileselector_mime_types_filter_append(mime_types, filter_name, ret) ELM_OBJ_FILESELECTOR_ID(ELM_OBJ_FILESELECTOR_SUB_ID_MIME_TYPES_FILTER_APPEND), EO_TYPECHECK(const char *, mime_types), EO_TYPECHECK(const char *, filter_name), EO_TYPECHECK(Eina_Bool *, ret) + +/** + * @def elm_obj_fileselector_filters_clear + * @since 1.8 + * + * Clear all filters registered + * + * + * @see elm_fileselector_mime_type_filter_append + */ +#define elm_obj_fileselector_filters_clear() ELM_OBJ_FILESELECTOR_ID(ELM_OBJ_FILESELECTOR_SUB_ID_FILTERS_CLEAR) + /** * @} */ diff --git a/legacy/elementary/src/lib/elc_fileselector_legacy.h b/legacy/elementary/src/lib/elc_fileselector_legacy.h index 505b787988..52edeea591 100644 --- a/legacy/elementary/src/lib/elc_fileselector_legacy.h +++ b/legacy/elementary/src/lib/elc_fileselector_legacy.h @@ -242,3 +242,36 @@ EAPI Eina_Bool elm_fileselector_selected_set(Evas_Object *obj, const * @ingroup Fileselector */ EAPI const char *elm_fileselector_selected_get(const Evas_Object *obj); + +/** + * Append mime types filter into filter list + * + * @param obj The file selector object + * @param mime_types comma(,) separated mime types to be allowed. + * @param filter_name The name to be displayed, @p mime_types will be displayed if NULL + * @return @c EINA_TRUE on success, @c EINA_FALSE on failure. + * + * @note a sub type of mime can be asterisk(*) + * @note mime type filter is only working with efreet now. + * @note first added filter will be the default filter at the moment. + * + * @see elm_need_efreet() + * @see elm_fileselector_filters_clear() + * + * @ingroup Fileselector + */ +EAPI Eina_Bool elm_fileselector_mime_types_filter_append(Evas_Object *obj, const char *mime_types, const char *filter_name); + +/** + * Clear all filters registered + * + * @param obj The file selector object + * + * @note If filter list is empty, file selector assume that all + * files are matched. + * + * @see elm_fileselector_mime_type_filter_append() + * + * @ingroup Fileselector + */ +EAPI void elm_fileselector_filters_clear(Evas_Object *obj); diff --git a/legacy/elementary/src/lib/elm_widget_fileselector.h b/legacy/elementary/src/lib/elm_widget_fileselector.h index d656d0a731..ad8c35ae68 100644 --- a/legacy/elementary/src/lib/elm_widget_fileselector.h +++ b/legacy/elementary/src/lib/elm_widget_fileselector.h @@ -14,6 +14,8 @@ * widgets which are a fileselector with some more logic on top. */ +typedef struct _Elm_Fileselector_Filter Elm_Fileselector_Filter; + /** * Base layout smart data extended with fileselector instance data. */ @@ -22,24 +24,28 @@ struct _Elm_Fileselector_Smart_Data { EINA_REFCOUNT; - Evas_Object *obj; - Evas_Object *path_entry; - Evas_Object *files_list; - Evas_Object *files_grid; - Evas_Object *up_button; - Evas_Object *home_button; - Evas_Object *spinner; - Evas_Object *ok_button; - Evas_Object *cancel_button; + Evas_Object *obj; + Evas_Object *path_entry; + Evas_Object *files_list; + Evas_Object *files_grid; + Evas_Object *up_button; + Evas_Object *home_button; + Evas_Object *spinner; + Evas_Object *filter_hoversel; + Evas_Object *ok_button; + Evas_Object *cancel_button; - const char *path; - const char *selection; - Ecore_Idler *sel_idler; + Eina_List *filter_list; + Elm_Fileselector_Filter *current_filter; - const char *path_separator; + const char *path; + const char *selection; + Ecore_Idler *sel_idler; + + const char *path_separator; #ifdef HAVE_EIO - Eio_File *current; + Eio_File *current; #endif Elm_Fileselector_Mode mode; @@ -72,6 +78,14 @@ typedef enum { ELM_FILE_LAST } Elm_Fileselector_Type; +struct _Elm_Fileselector_Filter +{ + const char *filter_name; + Elm_Fileselector_Smart_Data *sd; + + char **mime_types; +}; + /** * @} */