From 82a43998cb14e0845a506164b15c7f788c62abfd Mon Sep 17 00:00:00 2001 From: Tom Hacohen Date: Thu, 2 Apr 2015 10:37:37 +0100 Subject: [PATCH] Revert "Revert "Elm helper: add the posix regex validator."" Reapply the patch. Next commit will fix the break. This reverts commit 6f8be78ca04125f220c339145d700fc2e1a1f9c1. --- .../elementary/data/themes/edc/elm/entry.edc | 64 +++++++ legacy/elementary/src/bin/test.c | 2 + legacy/elementary/src/bin/test_entry.c | 164 ++++++++++++++++++ legacy/elementary/src/lib/Elementary.h.in | 2 + legacy/elementary/src/lib/Makefile.am | 4 +- legacy/elementary/src/lib/elm_entry.c | 56 +++++- legacy/elementary/src/lib/elm_entry.eo | 1 + legacy/elementary/src/lib/elm_entry.h | 1 + legacy/elementary/src/lib/elm_helper.c | 53 ++++++ legacy/elementary/src/lib/elm_helper.h | 108 ++++++++++++ legacy/elementary/src/lib/elm_widget_entry.h | 1 + 11 files changed, 454 insertions(+), 2 deletions(-) create mode 100644 legacy/elementary/src/lib/elm_helper.c create mode 100644 legacy/elementary/src/lib/elm_helper.h diff --git a/legacy/elementary/data/themes/edc/elm/entry.edc b/legacy/elementary/data/themes/edc/elm/entry.edc index cf836fcc36..4967f67e7a 100644 --- a/legacy/elementary/data/themes/edc/elm/entry.edc +++ b/legacy/elementary/data/themes/edc/elm/entry.edc @@ -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"; + } } } diff --git a/legacy/elementary/src/bin/test.c b/legacy/elementary/src/bin/test.c index a30109c2fb..4a8a35de8b 100644 --- a/legacy/elementary/src/bin/test.c +++ b/legacy/elementary/src/bin/test.c @@ -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); diff --git a/legacy/elementary/src/bin/test_entry.c b/legacy/elementary/src/bin/test_entry.c index 025e7c7153..3c87c8d636 100644 --- a/legacy/elementary/src/bin/test_entry.c +++ b/legacy/elementary/src/bin/test_entry.c @@ -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) { diff --git a/legacy/elementary/src/lib/Elementary.h.in b/legacy/elementary/src/lib/Elementary.h.in index 6e87bf0bb3..92e0adc92e 100644 --- a/legacy/elementary/src/lib/Elementary.h.in +++ b/legacy/elementary/src/lib/Elementary.h.in @@ -264,6 +264,8 @@ EAPI extern Elm_Version *elm_version; /* include deprecated calls last of all */ #include +#include + #ifdef __cplusplus } #endif diff --git a/legacy/elementary/src/lib/Makefile.am b/legacy/elementary/src/lib/Makefile.am index cd283800e3..cad85948f1 100644 --- a/legacy/elementary/src/lib/Makefile.am +++ b/legacy/elementary/src/lib/Makefile.am @@ -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 \ diff --git a/legacy/elementary/src/lib/elm_entry.c b/legacy/elementary/src/lib/elm_entry.c index 8c664e5d3c..3dace14d44 100644 --- a/legacy/elementary/src/lib/elm_entry.c +++ b/legacy/elementary/src/lib/elm_entry.c @@ -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 diff --git a/legacy/elementary/src/lib/elm_entry.eo b/legacy/elementary/src/lib/elm_entry.eo index 1a444be453..59f8209914 100644 --- a/legacy/elementary/src/lib/elm_entry.eo +++ b/legacy/elementary/src/lib/elm_entry.eo @@ -1232,6 +1232,7 @@ class Elm_Entry (Elm_Layout, Elm_Interface_Scrollable, Evas.Clickable_Interface, activated; changed; changed,user; + validate; } } diff --git a/legacy/elementary/src/lib/elm_entry.h b/legacy/elementary/src/lib/elm_entry.h index c38adf801e..c4dd8bdd95 100644 --- a/legacy/elementary/src/lib/elm_entry.h +++ b/legacy/elementary/src/lib/elm_entry.h @@ -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 diff --git a/legacy/elementary/src/lib/elm_helper.c b/legacy/elementary/src/lib/elm_helper.c new file mode 100644 index 0000000000..57a0423537 --- /dev/null +++ b/legacy/elementary/src/lib/elm_helper.c @@ -0,0 +1,53 @@ +#ifdef HAVE_CONFIG_H +# include "elementary_config.h" +#endif + +#include +#include + +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; +} diff --git a/legacy/elementary/src/lib/elm_helper.h b/legacy/elementary/src/lib/elm_helper.h new file mode 100644 index 0000000000..c09fd6fa26 --- /dev/null +++ b/legacy/elementary/src/lib/elm_helper.h @@ -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); + +/** + * @} + */ diff --git a/legacy/elementary/src/lib/elm_widget_entry.h b/legacy/elementary/src/lib/elm_widget_entry.h index c29275b057..4af06b9b9e 100644 --- a/legacy/elementary/src/lib/elm_widget_entry.h +++ b/legacy/elementary/src/lib/elm_widget_entry.h @@ -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 */