diff --git a/finch/gntrequest.c b/finch/gntrequest.c --- a/finch/gntrequest.c +++ b/finch/gntrequest.c @@ -388,10 +388,11 @@ purple_notify_close_with_handle(button); if (!g_object_get_data(G_OBJECT(button), "cancellation-function") && - !purple_request_fields_all_required_filled(fields)) { + (!purple_request_fields_all_required_filled(fields) || + !purple_request_fields_all_valid(fields))) { purple_notify_error(button, _("Error"), - _("You must fill all the required fields."), - _("The required fields are underlined.")); + _("You must properly fill all the required fields."), + _("The required fields are underlined.")); return; } diff --git a/libpurple/request.c b/libpurple/request.c --- a/libpurple/request.c +++ b/libpurple/request.c @@ -128,6 +128,9 @@ void *ui_data; char *tooltip; + + PurpleRequestFieldValidator validator; + void *validator_data; }; struct _PurpleRequestFields @@ -138,6 +141,8 @@ GList *required_fields; + GList *validated_fields; + void *ui_data; }; @@ -171,6 +176,7 @@ g_list_foreach(fields->groups, (GFunc)purple_request_field_group_destroy, NULL); g_list_free(fields->groups); g_list_free(fields->required_fields); + g_list_free(fields->validated_fields); g_hash_table_destroy(fields->fields); g_free(fields); } @@ -203,6 +209,11 @@ g_list_append(fields->required_fields, field); } + if (purple_request_field_is_validated(field)) { + fields->validated_fields = + g_list_append(fields->validated_fields, field); + } + } } @@ -231,6 +242,14 @@ return fields->required_fields; } +GList * +purple_request_fields_get_validated(const PurpleRequestFields *fields) +{ + g_return_val_if_fail(fields != NULL, NULL); + + return fields->validated_fields; +} + gboolean purple_request_fields_is_field_required(const PurpleRequestFields *fields, const char *id) @@ -274,18 +293,26 @@ { PurpleRequestField *field = (PurpleRequestField *)l->data; - switch (purple_request_field_get_type(field)) - { - case PURPLE_REQUEST_FIELD_STRING: - if (purple_request_field_string_get_value(field) == NULL || - *(purple_request_field_string_get_value(field)) == '\0') - return FALSE; + if (!purple_request_field_is_filled(field)) + return FALSE; + } - break; + return TRUE; +} - default: - break; - } +gboolean +purple_request_fields_all_valid(const PurpleRequestFields *fields) +{ + GList *l; + + g_return_val_if_fail(fields != NULL, FALSE); + + for (l = fields->validated_fields; l != NULL; l = l->next) + { + PurpleRequestField *field = (PurpleRequestField *)l->data; + + if (!purple_request_field_is_valid(field)) + return FALSE; } return TRUE; @@ -436,6 +463,12 @@ group->fields_list->required_fields = g_list_append(group->fields_list->required_fields, field); } + + if (purple_request_field_is_validated(field)) + { + group->fields_list->validated_fields = + g_list_append(group->fields_list->validated_fields, field); + } } field->group = group; @@ -657,6 +690,68 @@ return field->required; } +gboolean +purple_request_field_is_filled(const PurpleRequestField *field) +{ + g_return_val_if_fail(field != NULL, FALSE); + + switch (purple_request_field_get_type(field)) + { + case PURPLE_REQUEST_FIELD_STRING: + return (purple_request_field_string_get_value(field) != NULL && + *(purple_request_field_string_get_value(field)) != '\0'); + default: + return TRUE; + } +} + +void +purple_request_field_set_validator(PurpleRequestField *field, + PurpleRequestFieldValidator validator, void *user_data) +{ + g_return_if_fail(field != NULL); + + field->validator = validator; + field->validator_data = validator ? user_data : NULL; + + if (field->group != NULL) + { + if (validator) + { + field->group->fields_list->validated_fields = g_list_append( + field->group->fields_list->validated_fields, field); + } + else + { + field->group->fields_list->validated_fields = g_list_remove( + field->group->fields_list->validated_fields, field); + } + } +} + +gboolean +purple_request_field_is_validated(PurpleRequestField *field) +{ + g_return_val_if_fail(field != NULL, FALSE); + + return field->validator != NULL; +} + +gboolean +purple_request_field_is_valid(PurpleRequestField *field) +{ + g_return_val_if_fail(field != NULL, FALSE); + + if (!field->validator) + return TRUE; + + if (!purple_request_field_is_required(field) && + !purple_request_field_is_filled(field)) + return TRUE; + + return field->validator(field, field->validator_data); +} + PurpleRequestField * purple_request_field_string_new(const char *id, const char *text, const char *default_value, gboolean multiline) diff --git a/libpurple/request.h b/libpurple/request.h --- a/libpurple/request.h +++ b/libpurple/request.h @@ -150,6 +150,8 @@ typedef void (*PurpleRequestInputCb)(void *, const char *); +typedef gboolean (*PurpleRequestFieldValidator)(PurpleRequestField *field, void *user_data); + /** The type of callbacks passed to purple_request_action(). The first * argument is the @a user_data parameter; the second is the index in the list * of actions of the one chosen. @@ -219,6 +221,15 @@ GList *purple_request_fields_get_required(const PurpleRequestFields *fields); /** + * Returns a list of all validated fields. + * + * @param fields The fields list. + * + * @constreturn The list of validated fields. + */ +GList *purple_request_fields_get_validated(const PurpleRequestFields *fields); + +/** * Returns whether or not a field with the specified ID is required. * * @param fields The fields list. @@ -240,6 +251,15 @@ const PurpleRequestFields *fields); /** + * Returns whether or not all fields are valid. + * + * @param fields The fields list. + * + * @return TRUE if all fields are valid, or FALSE. + */ +gboolean purple_request_fields_all_valid(const PurpleRequestFields *fields); + +/** * Return the field with the specified ID. * * @param fields The fields list. @@ -534,6 +554,45 @@ gboolean purple_request_field_is_required(const PurpleRequestField *field); /** + * Checks, if specified field has value. + * + * @param field The field. + * + * @return TRUE if the field has value, or FALSE. + */ +gboolean purple_request_field_is_filled(const PurpleRequestField *field); + +/** + * Sets validator for a single field. + * + * @param field The field. + * @param validator The validator callback, NULL to disable validation. + * @param user_data The data to pass to the callback. + */ +void purple_request_field_set_validator(PurpleRequestField *field, + PurpleRequestFieldValidator validator, void *user_data); + +/** + * Returns whether or not field has validator set. + * + * @param field The field. + * + * @return TRUE if the field has validator, or FALSE. + */ +gboolean purple_request_field_is_validated(PurpleRequestField *field); + +/** + * Checks, if specified field is valid. + * + * Note: empty, not required fields are valid. + * + * @param field The field. + * + * @return TRUE, if the field is valid, FALSE otherwise. + */ +gboolean purple_request_field_is_valid(PurpleRequestField *field); + +/** * Returns the ui_data for a field. * * @param field The field. diff --git a/pidgin/gtkdialogs.c b/pidgin/gtkdialogs.c --- a/pidgin/gtkdialogs.c +++ b/pidgin/gtkdialogs.c @@ -879,6 +879,21 @@ pidgin_dialogs_im_with_user(account, username); } +static gboolean +pidgin_dialogs_im_name_validator(PurpleRequestField *field, void *_fields) +{ + PurpleRequestFields *fields = _fields; + PurpleAccount *account; + PurplePlugin *prpl; + const char *username; + + account = purple_request_fields_get_account(fields, "account"); + prpl = purple_find_prpl(purple_account_get_protocol_id(account)); + username = purple_request_fields_get_string(fields, "screenname"); + + return purple_validate(prpl, username); +} + void pidgin_dialogs_im(void) { @@ -894,6 +909,7 @@ field = purple_request_field_string_new("screenname", _("_Name"), NULL, FALSE); purple_request_field_set_type_hint(field, "screenname"); purple_request_field_set_required(field, TRUE); + purple_request_field_set_validator(field, pidgin_dialogs_im_name_validator, fields); purple_request_field_group_add_field(group, field); field = purple_request_field_account_new("account", _("_Account"), NULL); diff --git a/pidgin/gtkrequest.c b/pidgin/gtkrequest.c --- a/pidgin/gtkrequest.c +++ b/pidgin/gtkrequest.c @@ -769,10 +769,6 @@ static void req_entry_field_changed_cb(GtkWidget *entry, PurpleRequestField *field) { - PurpleRequestFieldGroup *group; - PurpleRequestFields *fields; - PidginRequestData *req_data; - if (purple_request_field_string_is_multiline(field)) { char *text; @@ -791,13 +787,22 @@ text = gtk_entry_get_text(GTK_ENTRY(entry)); purple_request_field_string_set_value(field, (*text == '\0') ? NULL : text); } +} + +static void +req_field_changed_cb(GtkWidget *widget, PurpleRequestField *field) +{ + PurpleRequestFieldGroup *group; + PurpleRequestFields *fields; + PidginRequestData *req_data; group = purple_request_field_get_group(field); fields = purple_request_field_group_get_fields_list(group); req_data = purple_request_fields_get_ui_data(fields); gtk_widget_set_sensitive(req_data->ok_button, - purple_request_fields_all_required_filled(fields)); + purple_request_fields_all_required_filled(fields) && + purple_request_fields_all_valid(fields)); } static void @@ -807,11 +812,10 @@ gtk_entry_set_activates_default(GTK_ENTRY(entry), TRUE); - if (purple_request_field_is_required(field)) - { - g_signal_connect(G_OBJECT(entry), "changed", - G_CALLBACK(req_entry_field_changed_cb), field); - } + g_signal_connect(G_OBJECT(entry), "changed", + G_CALLBACK(req_entry_field_changed_cb), field); + g_signal_connect(G_OBJECT(entry), "changed", + G_CALLBACK(req_field_changed_cb), field); if ((type_hint = purple_request_field_get_type_hint(field)) != NULL) { @@ -971,6 +975,8 @@ g_signal_connect(G_OBJECT(widget), "toggled", G_CALLBACK(field_bool_cb), field); + g_signal_connect(widget, "toggled", + G_CALLBACK(req_field_changed_cb), field); return widget; } @@ -1077,6 +1083,8 @@ field); gtk_widget_set_tooltip_text(widget, purple_request_field_get_tooltip(field)); + g_signal_connect(widget, "changed", + G_CALLBACK(req_field_changed_cb), field); return widget; } @@ -1587,6 +1595,9 @@ if (!purple_request_fields_all_required_filled(fields)) gtk_widget_set_sensitive(data->ok_button, FALSE); + if (!purple_request_fields_all_valid(fields)) + gtk_widget_set_sensitive(data->ok_button, FALSE); + pidgin_auto_parent_window(win); gtk_widget_show(win);