Revert "Revert "Elm helper: add the posix regex validator.""

Reapply the patch. Next commit will fix the break.

This reverts commit 6f8be78ca04125f220c339145d700fc2e1a1f9c1.
This commit is contained in:
Tom Hacohen 2015-04-02 10:37:37 +01:00
parent 71dc4b5392
commit 82a43998cb
11 changed files with 454 additions and 2 deletions

View File

@ -2,6 +2,20 @@ group { name: "elm/scroller/entry/default";
inherit: "elm/scroller/base/default";
image: "bg_glow_in.png" COMP;
parts {
part { name: "validation_glow";
type: RECT;
insert_before: "bg";
mouse_events: 0;
description { state: "default" 0.0;
color: 0 0 0 0;
}
description { state: "pass" 0.0;
color: 0 255 0 90;
}
description { state: "fail" 0.0;
color: 255 0 0 90;
}
}
part { name: "bg";
description { state: "default" 0.0;
color: DARK_GREY_BG_COLOR;
@ -113,6 +127,24 @@ group { name: "elm/scroller/entry/default";
transition: DECELERATE 0.3;
target: "glow";
}
program { name: "validation_fail";
signal: "validation,default,fail";
source: "elm";
action: STATE_SET "fail" 0.0;
target: "validation_glow";
}
program { name: "validation_pass";
signal: "validation,default,pass";
source: "elm";
action: STATE_SET "pass" 0.0;
target: "validation_glow";
}
program { name: "validation_off";
signal: "validation,default";
source: "elm";
action: STATE_SET "default" 0.0;
target: "validation_glow";
}
}
}
@ -124,6 +156,20 @@ group { name: "elm/scroller/entry_single/default";
data.item: "focus_highlight" "on";
parts {
part { name: "validation_glow";
type: RECT;
insert_before: "bg";
mouse_events: 0;
description { state: "default" 0.0;
color: 0 0 0 0;
}
description { state: "pass" 0.0;
color: 0 255 0 90;
}
description { state: "fail" 0.0;
color: 255 0 0 90;
}
}
part { name: "sb_vbar_base"; type: RECT;
description { state: "default" 0.0;
fixed: 1 1;
@ -315,6 +361,24 @@ group { name: "elm/scroller/entry_single/default";
transition: DECELERATE 0.3;
target: "glow";
}
program { name: "validation_fail";
signal: "validation,default,fail";
source: "elm";
action: STATE_SET "fail" 0.0;
target: "validation_glow";
}
program { name: "validation_pass";
signal: "validation,default,pass";
source: "elm";
action: STATE_SET "pass" 0.0;
target: "validation_glow";
}
program { name: "validation_off";
signal: "validation,default";
source: "elm";
action: STATE_SET "default" 0.0;
target: "validation_glow";
}
}
}

View File

@ -62,6 +62,7 @@ void test_entry5(void *data, Evas_Object *obj, void *event_info);
void test_entry6(void *data, Evas_Object *obj, void *event_info);
void test_entry7(void *data, Evas_Object *obj, void *event_info);
void test_entry8(void *data, Evas_Object *obj, void *event_info);
void test_entry_regex(void *data, Evas_Object *obj, void *event_info);
void test_entry_notepad(void *data, Evas_Object *obj, void *event_info);
void test_multibuttonentry(void *data, Evas_Object *obj, void *event_info);
void test_entry_anchor2(void *data, Evas_Object *obj, void *event_info);
@ -580,6 +581,7 @@ add_tests:
ADD_TEST(NULL, "Entries", "Entry 6", test_entry6);
ADD_TEST(NULL, "Entries", "Entry 7", test_entry7);
ADD_TEST(NULL, "Entries", "Entry 8", test_entry8);
ADD_TEST(NULL, "Entries", "Entry Regex", test_entry_regex);
ADD_TEST(NULL, "Entries", "Entry Notepad", test_entry_notepad);
ADD_TEST(NULL, "Entries", "Multibuttonentry", test_multibuttonentry);
ADD_TEST(NULL, "Entries", "Entry Anchor", test_entry_anchor);

View File

@ -2445,6 +2445,170 @@ test_entry8(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_in
evas_object_show(win);
}
typedef struct {
Evas_Object *en_regex;
Evas_Object *lb_regex;
Evas_Object *en_single;
Evas_Object *en_multi;
Elm_Validator_Regexp *re;
} _test_regex_data_t;
static void
_test_regex_data_del(void *data,
Evas *e EINA_UNUSED,
Evas_Object *obj EINA_UNUSED,
void *event_info EINA_UNUSED)
{
_test_regex_data_t *test_data = data;
if (test_data->re) elm_validator_regexp_free(test_data->re);
free(test_data);
}
static void
_test_regex_bt_cb(void *data,
Evas_Object *obj EINA_UNUSED,
void *event_info EINA_UNUSED)
{
int status;
_test_regex_data_t *test_data = data;
Eina_Strbuf *tmp;
if (test_data->re)
{
eo_do(test_data->en_single, eo_event_callback_del(ELM_ENTRY_EVENT_VALIDATE, elm_validator_regexp_helper, test_data->re));
eo_do(test_data->en_multi, eo_event_callback_del(ELM_ENTRY_EVENT_VALIDATE, elm_validator_regexp_helper, test_data->re));
elm_validator_regexp_free(test_data->re);
}
test_data->re = elm_validator_regexp_new(elm_entry_entry_get(test_data->en_regex), NULL);
status = elm_validator_regexp_status_get(test_data->re);
tmp = eina_strbuf_manage_new(strdup("Regex error: "));
switch (status)
{
case ELM_REG_NOERROR:
{
eina_strbuf_append(tmp, "No error. Regex maches to the Entrys text.");
break;
}
case ELM_REG_BADPAT:
{
eina_strbuf_append(tmp, "Invalid regular expression.");
break;
}
default:
break;
}
if (!status)
{
eo_do(test_data->en_single, eo_event_callback_add(ELM_ENTRY_EVENT_VALIDATE, elm_validator_regexp_helper, test_data->re));
eo_do(test_data->en_multi, eo_event_callback_add(ELM_ENTRY_EVENT_VALIDATE, elm_validator_regexp_helper, test_data->re));
}
elm_object_text_set(test_data->lb_regex, eina_strbuf_string_get(tmp));
eina_strbuf_free(tmp);
}
static inline Evas_Object *
_test_regex_entry_add(Evas_Object *parent, Eina_Bool is_singleline)
{
Evas_Object *entry = elm_entry_add(parent);
elm_entry_scrollable_set(entry, EINA_TRUE);
elm_entry_single_line_set(entry, is_singleline);
evas_object_size_hint_weight_set(entry, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
evas_object_size_hint_align_set(entry, EVAS_HINT_FILL, EVAS_HINT_FILL);
elm_entry_editable_set(entry, EINA_TRUE);
evas_object_show(entry);
return entry;
}
void
test_entry_regex(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
{
Evas_Object *win, *scr, *box;
Evas_Object *item, *label, *bt, *sep;
_test_regex_data_t *test_data;
#define REGEX "^[0-9]*$"
test_data = malloc(sizeof(_test_regex_data_t));
win = elm_win_util_standard_add("Entry", "Entry Regex Test");
elm_win_autodel_set(win, EINA_TRUE);
evas_object_event_callback_add(win, EVAS_CALLBACK_DEL,
_test_regex_data_del, test_data);
scr = elm_scroller_add(win);
elm_scroller_bounce_set(scr, EINA_FALSE, EINA_TRUE);
elm_scroller_policy_set(scr, ELM_SCROLLER_POLICY_OFF, ELM_SCROLLER_POLICY_AUTO);
evas_object_size_hint_weight_set(scr, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
elm_win_resize_object_add(win, scr);
evas_object_show(scr);
box = elm_box_add(win);
evas_object_size_hint_weight_set(box, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
elm_box_homogeneous_set(box, EINA_FALSE);
elm_object_content_set(scr, box);
evas_object_show(box);
label = elm_label_add(box);
elm_object_text_set(label, "Regular Expression");
elm_box_pack_end(box, label);
evas_object_show(label);
item = elm_box_add(win);
evas_object_size_hint_weight_set(item, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
evas_object_size_hint_align_set(item, EVAS_HINT_FILL, EVAS_HINT_FILL);
elm_box_horizontal_set(item, EINA_TRUE);
elm_box_homogeneous_set(item, EINA_FALSE);
evas_object_show(item);
elm_box_pack_end(box, item);
test_data->en_regex = _test_regex_entry_add(item, EINA_TRUE);
elm_box_pack_end(item, test_data->en_regex);
bt = elm_button_add(item);
elm_object_text_set(bt, "Set");
evas_object_smart_callback_add(bt, "clicked", _test_regex_bt_cb, test_data);
evas_object_show(bt);
elm_box_pack_end(item, bt);
test_data->lb_regex = elm_label_add(box);
elm_object_text_set(test_data->lb_regex, "Regex error: no error.");
elm_box_pack_end(box, test_data->lb_regex);
evas_object_show(test_data->lb_regex);
sep = elm_separator_add(box);
elm_separator_horizontal_set(sep, EINA_TRUE);
evas_object_show(sep);
elm_box_pack_end(box, sep);
label = elm_label_add(box);
elm_object_text_set(label, "Test regex in single line entry");
elm_box_pack_end(box, label);
evas_object_show(label);
test_data->en_single = _test_regex_entry_add(box, EINA_TRUE);
elm_box_pack_end(box, test_data->en_single);
label = elm_label_add(box);
elm_object_text_set(label, "Test regex in multi line entry");
elm_box_pack_end(box, label);
evas_object_show(label);
test_data->en_multi = _test_regex_entry_add(box, EINA_FALSE);
elm_box_pack_end(box, test_data->en_multi);
test_data->re = elm_validator_regexp_new(REGEX, NULL);
elm_entry_entry_set(test_data->en_regex, REGEX);
eo_do(test_data->en_single, eo_event_callback_add(ELM_ENTRY_EVENT_VALIDATE, elm_validator_regexp_helper, test_data->re));
eo_do(test_data->en_multi, eo_event_callback_add(ELM_ENTRY_EVENT_VALIDATE, elm_validator_regexp_helper, test_data->re));
evas_object_resize(win, 400, 400);
evas_object_show(win);
#undef REGEX
}
static void
_scrolled_entry_clear(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
{

View File

@ -264,6 +264,8 @@ EAPI extern Elm_Version *elm_version;
/* include deprecated calls last of all */
#include <elm_deprecated.h>
#include <elm_helper.h>
#ifdef __cplusplus
}
#endif

View File

@ -383,7 +383,8 @@ elm_web_legacy.h \
elm_win.h \
elm_win_common.h \
elm_win_eo.h \
elm_win_legacy.h
elm_win_legacy.h \
elm_helper.h
includesubdir = $(includedir)/elementary-@VMAJ@/
libelementary_la_SOURCES = \
@ -495,6 +496,7 @@ elm_video.c \
elm_web2.c \
elm_widget.c \
elm_win.c \
elm_helper.c \
els_box.c \
els_cursor.c \
els_tooltip.c \

View File

@ -282,6 +282,25 @@ _elm_entry_guide_update(Evas_Object *obj,
sd->has_text = has_text;
}
static void
_validate(Evas_Object *obj)
{
ELM_ENTRY_DATA_GET(obj, sd);
Eina_Bool res;
Elm_Validate_Content vc;
Eina_Strbuf *buf;
if (sd->validators == 0) return;
vc.text = edje_object_part_text_get(sd->entry_edje, "elm.text");
eo_do(obj, res = eo_event_callback_call(ELM_ENTRY_EVENT_VALIDATE, (void *)&vc));
buf = eina_strbuf_new();
eina_strbuf_append_printf(buf, "validation,%s,%s", vc.signal, res == EO_CALLBACK_STOP ? "fail" : "pass");
edje_object_signal_emit(sd->scr_edje, eina_strbuf_string_get(buf), "elm");
eina_tmpstr_del(vc.signal);
eina_strbuf_free(buf);
}
static Elm_Entry_Markup_Filter *
_filter_new(Elm_Entry_Filter_Cb func,
void *data)
@ -1081,6 +1100,7 @@ _elm_entry_elm_widget_on_focus(Eo *obj, Elm_Entry_Data *sd)
elm_win_keyboard_mode_set(top, ELM_WIN_KEYBOARD_ON);
evas_object_smart_callback_call(obj, SIG_FOCUSED, NULL);
_return_key_enabled_check(obj);
_validate(obj);
}
else
{
@ -1102,6 +1122,7 @@ _elm_entry_elm_widget_on_focus(Eo *obj, Elm_Entry_Data *sd)
edje_object_part_text_select_none(sd->entry_edje, "elm.text");
}
}
edje_object_signal_emit(sd->scr_edje, "validation,default", "elm");
}
return EINA_TRUE;
@ -1873,6 +1894,8 @@ _entry_changed_handle(void *data,
else
_elm_entry_guide_update(data, EINA_FALSE);
}
_validate(data);
/* callback - this could call callbacks that delete the
* entry... thus... any access to sd after this could be
* invalid */
@ -3671,6 +3694,35 @@ elm_entry_add(Evas_Object *parent)
return obj;
}
static Eina_Bool
_cb_added(void *data EINA_UNUSED,
Eo *obj,
const Eo_Event_Description *desc EINA_UNUSED,
void *event_info)
{
const Eo_Callback_Array_Item *event = event_info;
ELM_ENTRY_DATA_GET(obj, sd);
if (event->desc == ELM_ENTRY_EVENT_VALIDATE)
sd->validators++;
return EO_CALLBACK_CONTINUE;
}
static Eina_Bool
_cb_deled(void *data EINA_UNUSED,
Eo *obj,
const Eo_Event_Description *desc EINA_UNUSED,
void *event_info)
{
const Eo_Callback_Array_Item *event = event_info;
ELM_ENTRY_DATA_GET(obj, sd);
if (event->desc == ELM_ENTRY_EVENT_VALIDATE)
sd->validators--;
return EO_CALLBACK_CONTINUE;
}
EOLIAN static void
_elm_entry_eo_base_constructor(Eo *obj, Elm_Entry_Data *_pd EINA_UNUSED)
{
@ -3678,7 +3730,9 @@ _elm_entry_eo_base_constructor(Eo *obj, Elm_Entry_Data *_pd EINA_UNUSED)
eo_do(obj,
evas_obj_type_set(MY_CLASS_NAME_LEGACY),
evas_obj_smart_callbacks_descriptions_set(_smart_callbacks),
elm_interface_atspi_accessible_role_set(ELM_ATSPI_ROLE_ENTRY));
elm_interface_atspi_accessible_role_set(ELM_ATSPI_ROLE_ENTRY),
eo_event_callback_add(EO_EV_CALLBACK_ADD, _cb_added, NULL),
eo_event_callback_add(EO_EV_CALLBACK_DEL, _cb_deled, NULL));
}
EOLIAN static void

View File

@ -1232,6 +1232,7 @@ class Elm_Entry (Elm_Layout, Elm_Interface_Scrollable, Evas.Clickable_Interface,
activated;
changed;
changed,user;
validate;
}
}

View File

@ -274,6 +274,7 @@
* @li "theme,changed": Called when the theme is changed.
* @li "undo,request": Called on undo request.
* @li "rejected": Called when some of inputs are rejected by the filter. (since 1.9)
* @li "validate": Called when entry text ready to validate. (since 1.14)
*
* Default content parts of the entry items that you can use for are:
* @li "icon" - An icon in the entry

View File

@ -0,0 +1,53 @@
#ifdef HAVE_CONFIG_H
# include "elementary_config.h"
#endif
#include <Elementary.h>
#include <regex.h>
struct _Elm_Validator_Regexp
{
Eina_Stringshare *signal;
int status;
regex_t regex;
};
EAPI Elm_Validator_Regexp *
elm_validator_regexp_new(const char *pattern, const char *signal)
{
Elm_Validator_Regexp *validator;
validator = calloc(1, sizeof(Elm_Validator_Regexp));
validator->signal = eina_stringshare_add(signal ? signal : "default");
validator->status = regcomp(&validator->regex, pattern, REG_EXTENDED | REG_NOSUB) ? ELM_REG_BADPAT : ELM_REG_NOERROR;
return validator;
}
EAPI void
elm_validator_regexp_free(Elm_Validator_Regexp *validator)
{
eina_stringshare_del(validator->signal);
regfree(&validator->regex);
free(validator);
}
EAPI Elm_Regexp_Status
elm_validator_regexp_status_get(Elm_Validator_Regexp *validator)
{
return validator->status;
}
EAPI Eina_Bool
elm_validator_regexp_helper(void *data,
Eo *obj EINA_UNUSED,
const Eo_Event_Description *desc EINA_UNUSED,
void *event_info)
{
Elm_Validate_Content *vc = event_info;
Elm_Validator_Regexp *validator = (Elm_Validator_Regexp *)data;
validator->status = regexec(&validator->regex, vc->text, (size_t)0, NULL, 0) ? ELM_REG_NOMATCH : ELM_REG_NOERROR;
vc->signal = validator->signal;
return validator->status ? EO_CALLBACK_STOP : EO_CALLBACK_CONTINUE;
}

View File

@ -0,0 +1,108 @@
/**
* @defgroup Helper Helper
* @ingroup Elementary
*
* The validation helper feature.
*
* @{
*/
struct _Elm_Validate_Content
{
const char *text;
Eina_Tmpstr *signal;
};
/**
* Data for the elm_validator_regexp_helper()
*/
typedef struct _Elm_Validate_Content Elm_Validate_Content;
/**
* The Regexp validator data.
*/
typedef struct _Elm_Validator_Regexp Elm_Validator_Regexp;
/**
* @brief Enumeration that defines the regex error codes
* @since 1.14
*/
typedef enum
{
/** Regex maches to the Entrys text. */
ELM_REG_NOERROR = 0,
/** Failed to match. */
ELM_REG_NOMATCH,
/** Invalid regular expression. */
ELM_REG_BADPAT,
} Elm_Regexp_Status;
/**
* @brief Create a new regex validator.
* General designed for validate inputed entry text.
*
* @param pattern The regex pattern
* @param signal The part of signal name, which will be emited to style
* @return The regex validator
*
* @see elm_validator_regexp_del()
* @see elm_validator_regex_regex_set()
* @see elm_validator_regexp_status_get()
* @see elm_validator_regexp_helper()
*
* @since 1.14
*/
EAPI Elm_Validator_Regexp *
elm_validator_regexp_new(const char *pattern, const char *signal) EINA_ARG_NONNULL(1);
/**
* @brief Delete the existing regex validator.
*
* @param validator The given validator
*
* @see elm_validator_regexp_add()
*
* @since 1.14
*/
EAPI void
elm_validator_regexp_free(Elm_Validator_Regexp *validator) EINA_ARG_NONNULL(1);
/**
* @brief Get the validation status.
*
* @param The given validator
*
* @note All return value see here: http://www.gnu.org/software/libc/manual/html_node/Regular-Expressions.html
*
* @since 1.14
*/
EAPI Elm_Regexp_Status
elm_validator_regexp_status_get(Elm_Validator_Regexp *validator) EINA_ARG_NONNULL(1);
/**
* @brief The regex validator. Used as callback to validate event.
*
* Example:
* @code
* extern Evas_Object *parent;
* Evas_Object *entry;
* Elm_Validator_Regexp *re;
*
* //add validator
* entry = elm_entry_add(parent);
* re = elm_validator_regexp_add("^[0-9]*$");
* eo_do(entry, eo_event_callback_add(ELM_ENTRY_EVENT_VALIDATE, elm_validator_regexp_helper, re));
*
* //delete validator
* eo_do(entry, eo_event_callback_del(ELM_ENTRY_EVENT_VALIDATE, elm_validator_regexp_helper, re));
* @endcode
*
* @see elm_validator_regexp_add()
* @see elm_validotor_regex_regex_set()
* @since 1.14
*/
EAPI Eina_Bool
elm_validator_regexp_helper(void *data, Eo *obj, const Eo_Event_Description *desc, void *event_info);
/**
* @}
*/

View File

@ -72,6 +72,7 @@ struct _Elm_Entry_Data
void *input_panel_imdata;
int input_panel_imdata_len;
int input_panel_layout_variation;
int validators;
struct
{
Evas_Object *hover_parent; /**< hover parent object. entry is a hover parent object by default */