fileselector : Add elm_fileselector_custom_filter_append to support custom filter
authorRyuan Choi <ryuan.choi@gmail.com>
Sun, 29 Dec 2013 04:23:17 +0000 (13:23 +0900)
committerCarsten Haitzler (Rasterman) <raster@rasterman.com>
Sun, 29 Dec 2013 04:23:17 +0000 (13:23 +0900)
Summary:
Now, application developers can decide whether files and directories to show in
fileselector view.

Reviewers: seoz, raster

Reviewed By: raster

Differential Revision: https://phab.enlightenment.org/D416

src/bin/test_fileselector.c
src/lib/elc_fileselector.c
src/lib/elc_fileselector_common.h
src/lib/elc_fileselector_eo.h
src/lib/elc_fileselector_legacy.h
src/lib/elm_widget_fileselector.h

index d72343ac54cdfaae7b10ff1912e168d65df0939a..b5fedc5f60c0beb13cd12d7fad2d6cabd3c4ef37 100644 (file)
@@ -474,6 +474,14 @@ _thumbnail_size_option_create(Evas_Object *parent, Evas_Object *fs)
    return frame;
 }
 
+static Eina_Bool
+_all_filter(const char *path  EINA_UNUSED,
+            Eina_Bool dir     EINA_UNUSED,
+            void *data        EINA_UNUSED)
+{
+   return EINA_TRUE;
+}
+
 void
 test_fileselector(void *data       EINA_UNUSED,
                   Evas_Object *obj EINA_UNUSED,
@@ -507,6 +515,7 @@ test_fileselector(void *data       EINA_UNUSED,
    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");
+   elm_fileselector_custom_filter_append(fs, _all_filter, NULL, "All Files");
 
    /* allow fs to expand in x & y */
    evas_object_size_hint_weight_set(fs, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
index f15d20eda99d57f396dc9810e0449e40c18919ec..846b9cf56077e90e88fa127ad7e672e3a5b3ce27 100644 (file)
@@ -4,7 +4,6 @@
  *  - user defined icon/label cb
  *  - show/hide/add buttons ???
  *  - Pattern Filter support
- *  - Custom Filter support
  */
 #ifdef HAVE_CONFIG_H
 # include "elementary_config.h"
@@ -304,20 +303,19 @@ _mime_type_matched(const char *mime_filter, const char *mime_type)
 }
 
 static Eina_Bool
-_check_filters(const Elm_Fileselector_Filter *filter, const char *file_name)
+_check_mime_type_filter(const Elm_Fileselector_Filter *filter,
+                        const char *file_name)
 {
    const char *mime_type = NULL;
    int i;
 
-   if (!filter) return EINA_TRUE;
-
    mime_type = efreet_mime_type_get(file_name);
 
    if (!mime_type) return EINA_FALSE;
 
-   for (i = 0; filter->mime_types[i]; ++i)
+   for (i = 0; filter->filter.mime_types[i]; ++i)
      {
-        if (_mime_type_matched(filter->mime_types[i], mime_type))
+        if (_mime_type_matched(filter->filter.mime_types[i], mime_type))
           return EINA_TRUE;
      }
    return EINA_FALSE;
@@ -329,17 +327,34 @@ _ls_filter_cb(void *data,
               const Eina_File_Direct_Info *info)
 {
    Listing_Request *lreq = data;
+   Elm_Fileselector_Filter *cf;
+   Eina_Bool dir = EINA_FALSE;
 
    if (!lreq->sd->hidden_visible && info->path[info->name_start] == '.')
      return EINA_FALSE;
 
-   if (lreq->sd->only_folder && info->type != EINA_FILE_DIR)
-     return EINA_FALSE;
+   if (info->type == EINA_FILE_DIR)
+     dir = EINA_TRUE;
 
-   if (info->type != EINA_FILE_DIR && !_check_filters(lreq->sd->current_filter, info->path))
+   if (lreq->sd->only_folder && dir)
      return EINA_FALSE;
 
-   return EINA_TRUE;
+   cf = lreq->sd->current_filter;
+   if (!cf)
+     return EINA_TRUE;
+
+   switch (cf->filter_type)
+     {
+      case ELM_FILESELECTOR_MIME_FILTER:
+         return dir || _check_mime_type_filter(cf, info->path);
+      case ELM_FILESELECTOR_CUSTOM_FILTER:
+         return cf->filter.custom->func(info->path, dir,
+                                        cf->filter.custom->data);
+      default:
+         return EINA_FALSE;
+     }
+
+   return EINA_FALSE;
 }
 
 static const char *
@@ -1164,16 +1179,35 @@ _resource_created(void *data, int type, void *ev)
    Evas_Object *obj = data;
    Eio_Monitor_Event *event = ev;
    int itcn = ELM_FILE_UNKNOW;
+   Eina_Bool dir = EINA_FALSE;
 
    ELM_FILESELECTOR_DATA_GET(obj, sd);
 
    if (type == EIO_MONITOR_DIRECTORY_CREATED)
+     dir = EINA_TRUE;
+
+   Elm_Fileselector_Filter *cf = sd->current_filter;
+   if (cf)
+     {
+        switch (cf->filter_type)
+          {
+           case ELM_FILESELECTOR_MIME_FILTER:
+              if (!dir && !_check_mime_type_filter(cf, event->filename))
+                return ECORE_CALLBACK_PASS_ON;
+              break;
+           case ELM_FILESELECTOR_CUSTOM_FILTER:
+              if (!cf->filter.custom->func(event->filename, dir, cf->filter.custom->data))
+                return ECORE_CALLBACK_PASS_ON;
+              break;
+           default:
+              break;
+          }
+     }
+
+   if (dir)
      itcn = ELM_DIRECTORY;
    else
      {
-        if (!_check_filters(sd->current_filter, event->filename))
-          return ECORE_CALLBACK_PASS_ON;
-
         if (evas_object_image_extension_can_load_get(event->filename))
           itcn = ELM_FILE_IMAGE;
      }
@@ -1410,8 +1444,13 @@ _elm_fileselector_smart_del(Eo *obj EINA_UNUSED, void *_pd, va_list *list EINA_U
      {
         eina_stringshare_del(filter->filter_name);
 
-        free(filter->mime_types[0]);
-        free(filter->mime_types);
+        if (filter->filter_type == ELM_FILESELECTOR_MIME_FILTER)
+          {
+             free(filter->filter.mime_types[0]);
+             free(filter->filter.mime_types);
+          }
+        else
+          free(filter->filter.custom);
 
         free(filter);
      }
@@ -1892,6 +1931,18 @@ _selected_paths_get(Eo *obj __UNUSED__, void *_pd, va_list *list)
      *ret = NULL;
 }
 
+static Elm_Fileselector_Filter *
+_filter_add(Elm_Fileselector_Smart_Data *sd, const char *filter_name)
+{
+   Elm_Fileselector_Filter *ff;
+   ff = malloc(sizeof(Elm_Fileselector_Filter));
+
+   ff->filter_name = eina_stringshare_add(filter_name);
+   ff->sd = sd;
+
+   return ff;
+}
+
 EAPI Eina_Bool
 elm_fileselector_mime_types_filter_append(Evas_Object *obj, const char *mime_type, const char *filter_name)
 {
@@ -1917,17 +1968,65 @@ _mime_types_filter_append(Eo *obj, void *_pd, va_list *list)
 
    sd = _pd;
 
-   ff = malloc(sizeof(Elm_Fileselector_Filter));
-   if (!ff) goto end;
+   ff = _filter_add(sd, filter_name ? filter_name : mime_types);
+   ff->filter_type = ELM_FILESELECTOR_MIME_FILTER;
 
-   if (filter_name)
-     ff->filter_name = eina_stringshare_add(filter_name);
-   else
-     ff->filter_name = eina_stringshare_add(mime_types);
+   ff->filter.mime_types = eina_str_split(mime_types, ",", 0);
 
-   ff->sd = sd;
+   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_filter_changed, ff);
 
-   ff->mime_types = eina_str_split(mime_types, ",", 0);
+   sd->filter_list = eina_list_append(sd->filter_list, ff);
+
+   _populate(obj, sd->path, NULL, NULL);
+
+   if (need_theme)
+     eo_do(obj, elm_wdg_theme(NULL));
+
+   int_ret = EINA_TRUE;
+
+end:
+   if (ret) *ret = int_ret;
+}
+
+EAPI Eina_Bool
+elm_fileselector_custom_filter_append(Evas_Object *obj, Elm_Fileselector_Filter_Func func, void *data, const char *filter_name)
+{
+   ELM_FILESELECTOR_CHECK(obj) EINA_FALSE;
+   Eina_Bool ret = EINA_FALSE;
+   eo_do(obj, elm_obj_fileselector_custom_filter_append(func, data, filter_name, &ret));
+   return ret;
+}
+
+static void
+_custom_filter_append(Eo *obj, void *_pd, va_list *list)
+{
+   Elm_Fileselector_Filter_Func func = va_arg(*list, Elm_Fileselector_Filter_Func);
+   void *data = va_arg(*list, void *);
+   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 (!func) goto end;
+
+   sd = _pd;
+
+   ff = _filter_add(sd, filter_name ? filter_name : "custom");
+   ff->filter_type = ELM_FILESELECTOR_CUSTOM_FILTER;
+
+   ff->filter.custom = malloc(sizeof(Elm_Fileselector_Filter_Func));
+   ff->filter.custom->func = func;
+   ff->filter.custom->data = data;
 
    if (!sd->filter_list)
      {
@@ -1946,7 +2045,6 @@ _mime_types_filter_append(Eo *obj, void *_pd, va_list *list)
      eo_do(obj, elm_wdg_theme(NULL));
 
    int_ret = EINA_TRUE;
-
 end:
    if (ret) *ret = int_ret;
 }
@@ -1968,8 +2066,13 @@ _filters_clear(Eo *obj, void *_pd, va_list *list EINA_UNUSED)
      {
         eina_stringshare_del(filter->filter_name);
 
-        free(filter->mime_types[0]);
-        free(filter->mime_types);
+        if (filter->filter_type == ELM_FILESELECTOR_MIME_FILTER)
+          {
+             free(filter->filter.mime_types[0]);
+             free(filter->filter.mime_types);
+          }
+        else
+          free(filter->filter.custom);
 
         free(filter);
      }
@@ -2216,6 +2319,7 @@ _class_constructor(Eo_Class *klass)
         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_SELECTED_PATHS_GET), _selected_paths_get),
         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_CUSTOM_FILTER_APPEND), _custom_filter_append),
         EO_OP_FUNC(ELM_OBJ_FILESELECTOR_ID(ELM_OBJ_FILESELECTOR_SUB_ID_FILTERS_CLEAR), _filters_clear),
         EO_OP_FUNC(ELM_OBJ_FILESELECTOR_ID(ELM_OBJ_FILESELECTOR_SUB_ID_HIDDEN_VISIBLE_SET), _hidden_visible_set),
         EO_OP_FUNC(ELM_OBJ_FILESELECTOR_ID(ELM_OBJ_FILESELECTOR_SUB_ID_HIDDEN_VISIBLE_GET), _hidden_visible_get),
@@ -2282,6 +2386,7 @@ static const Eo_Op_Description op_desc[] = {
      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_SELECTED_PATHS_GET, "Get the currently selected item's (full) path, 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_CUSTOM_FILTER_APPEND, "Append custom filter"),
      EO_OP_DESCRIPTION(ELM_OBJ_FILESELECTOR_SUB_ID_FILTERS_CLEAR, "Clear filters"),
      EO_OP_DESCRIPTION(ELM_OBJ_FILESELECTOR_SUB_ID_HIDDEN_VISIBLE_SET, "Enable or disable visibility of hidden files/directories in the file selector widget."),
      EO_OP_DESCRIPTION(ELM_OBJ_FILESELECTOR_SUB_ID_HIDDEN_VISIBLE_GET, "Get if visibility of hidden files/directories in the file selector widget is enabled or disabled."),
index 73fd30ddb2ccbc04382fa5835c14cb6a531797b1..8b12c922f9a0836d3f28ee62ae8c56244e3bcd8f 100644 (file)
@@ -21,3 +21,5 @@ typedef enum
    ELM_FILESELECTOR_SORT_BY_MODIFIED_DESC,
    ELM_FILESELECTOR_SORT_LAST /**< sentinel (helper) value, not used */
 } Elm_Fileselector_Sort;
+
+typedef Eina_Bool (*Elm_Fileselector_Filter_Func)(const char *path, Eina_Bool dir, void *data);
index b0696f8d3af782b883558d010592b19d79e31826..b8a38f94feeedf3887120c7739b90fc39e5c2370 100644 (file)
@@ -29,6 +29,7 @@ enum
    ELM_OBJ_FILESELECTOR_SUB_ID_SELECTED_SET,
    ELM_OBJ_FILESELECTOR_SUB_ID_SELECTED_PATHS_GET,
    ELM_OBJ_FILESELECTOR_SUB_ID_MIME_TYPES_FILTER_APPEND,
+   ELM_OBJ_FILESELECTOR_SUB_ID_CUSTOM_FILTER_APPEND,
    ELM_OBJ_FILESELECTOR_SUB_ID_FILTERS_CLEAR,
    ELM_OBJ_FILESELECTOR_SUB_ID_HIDDEN_VISIBLE_SET,
    ELM_OBJ_FILESELECTOR_SUB_ID_HIDDEN_VISIBLE_GET,
@@ -268,6 +269,20 @@ enum
  */
 #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_custom_filter_append
+ * @since 1.9
+ *
+ * Append custom filter into filter list
+ *
+ * @param[in] mime_types
+ * @param[in] filter_name
+ * @param[out] ret
+ *
+ * @see elm_fileselector_custom_filter_append
+ */
+#define elm_obj_fileselector_custom_filter_append(func, data, filter_name, ret) ELM_OBJ_FILESELECTOR_ID(ELM_OBJ_FILESELECTOR_SUB_ID_CUSTOM_FILTER_APPEND), EO_TYPECHECK(Elm_Fileselector_Filter_Func, func), EO_TYPECHECK(void *, data), EO_TYPECHECK(const char *, filter_name), EO_TYPECHECK(Eina_Bool *, ret)
+
 /**
  * @def elm_obj_fileselector_filters_clear
  * @since 1.8
index a59936eb61b41d82b32206ce242b0efa32463eec..aff345681dd640a5a5e5b0ad7d245050c1edf9d9 100644 (file)
@@ -319,6 +319,22 @@ EAPI const Eina_List      *elm_fileselector_selected_paths_get(const Evas_Object
  */
 EAPI Eina_Bool             elm_fileselector_mime_types_filter_append(Evas_Object *obj, const char *mime_types, const char *filter_name);
 
+/**
+ * Append custom filter into filter list
+ *
+ * @param obj The file selector object
+ * @param func The function to call when manipulating files and directories.
+ * @param data The data to be passed to this @p func call.
+ * @param filter_name The name to be displayed, "custom" will be displayed if NULL
+ * @return @c EINA_TRUE on success, @c EINA_FALSE on failure.
+ *
+ * @note first added filter will be the default filter at the moment.
+ *
+ * @since 1.9
+ * @ingroup Fileselector
+ */
+EAPI Eina_Bool             elm_fileselector_custom_filter_append(Evas_Object *obj, Elm_Fileselector_Filter_Func func, void *data, const char *filter_name);
+
 /**
  * Clear all filters registered
  *
index c52948d1277eaf932ef34e5a54641fc078e9ca45..2991485539b98f808100e8eba56533ea7980386c 100644 (file)
@@ -98,12 +98,30 @@ typedef enum {
    ELM_FILE_LAST
 } Elm_Fileselector_Type;
 
+typedef enum {
+   ELM_FILESELECTOR_MIME_FILTER = 0,
+   ELM_FILESELECTOR_CUSTOM_FILTER,
+   ELM_FILESELECTOR_FILTER_LAST
+} Elm_Fileselector_Filter_Type;
+
+typedef struct _Elm_Fileselector_Custom_Filter Elm_Fileselector_Custom_Filter;
+struct _Elm_Fileselector_Custom_Filter
+{
+   Elm_Fileselector_Filter_Func  func;
+   void                         *data;
+};
+
 struct _Elm_Fileselector_Filter
 {
-   const char                   *filter_name;
-   Elm_Fileselector_Smart_Data  *sd;
+   const char                         *filter_name;
+   Elm_Fileselector_Smart_Data        *sd;
+
+   union {
+      char                           **mime_types;
+      Elm_Fileselector_Custom_Filter  *custom;
+   } filter;
 
-   char                        **mime_types;
+   Elm_Fileselector_Filter_Type        filter_type;
 };
 
 /**