--- a/finch/gntrequest.c Thu Mar 16 22:36:19 2023 -0500
+++ b/finch/gntrequest.c Thu Mar 16 22:50:08 2023 -0500
@@ -379,7 +379,7 @@
if (!g_object_get_data(G_OBJECT(button), "cancellation-function") &&
(!purple_request_page_all_required_filled(page) ||
- !purple_request_page_all_valid(page))) {
+ !purple_request_page_is_valid(page))) { purple_notify_error(button, _("Error"),
_("You must properly fill all the required fields."),
_("The required fields are underlined."), NULL);
--- a/libpurple/purplerequestgroup.c Thu Mar 16 22:36:19 2023 -0500
+++ b/libpurple/purplerequestgroup.c Thu Mar 16 22:50:08 2023 -0500
@@ -32,11 +32,13 @@
+ GHashTable *invalid_fields; static GParamSpec *properties[N_PROPERTIES] = {NULL, };
@@ -53,6 +55,31 @@
/******************************************************************************
+ *****************************************************************************/ +purple_request_group_notify_field_cb(GObject *obj, + G_GNUC_UNUSED GParamSpec *pspec, + PurpleRequestGroup *group = PURPLE_REQUEST_GROUP(data); + PurpleRequestField *field = PURPLE_REQUEST_FIELD(obj); + gboolean before, after; + before = purple_request_group_is_valid(group); + if(purple_request_field_is_valid(field, NULL)) { + g_hash_table_remove(group->invalid_fields, field); + g_hash_table_add(group->invalid_fields, field); + after = purple_request_group_is_valid(group); + g_object_notify_by_pspec(G_OBJECT(group), properties[PROP_VALID]); +/****************************************************************************** * GListModel Implementation
*****************************************************************************/
@@ -104,6 +131,9 @@
g_value_set_string(value, purple_request_group_get_title(group));
+ g_value_set_boolean(value, purple_request_group_is_valid(group)); G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
@@ -133,12 +163,14 @@
g_list_free_full(group->fields, g_object_unref);
+ g_clear_pointer(&group->invalid_fields, g_hash_table_destroy); G_OBJECT_CLASS(purple_request_group_parent_class)->finalize(obj);
-purple_request_group_init(G_GNUC_UNUSED PurpleRequestGroup *group) {
+purple_request_group_init(PurpleRequestGroup *group) { + group->invalid_fields = g_hash_table_new(g_direct_hash, g_direct_equal); @@ -162,6 +194,19 @@
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
+ * PurpleRequestGroup:valid: + * Whether all fields in a group are valid. + properties[PROP_VALID] = g_param_spec_boolean( + "Whether all fields in a group are valid.", + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_properties(obj_class, N_PROPERTIES, properties);
@@ -216,6 +261,10 @@
position = g_list_length(group->fields);
group->fields = g_list_append(group->fields, field);
+ purple_request_group_notify_field_cb(G_OBJECT(field), NULL, group); + g_signal_connect(field, "notify::valid", + G_CALLBACK(purple_request_group_notify_field_cb), group); if(PURPLE_IS_REQUEST_PAGE(group->page)) {
_purple_request_page_add_field(group->page, field);
@@ -248,3 +297,10 @@
+purple_request_group_is_valid(PurpleRequestGroup *group) { + g_return_val_if_fail(PURPLE_IS_REQUEST_GROUP(group), FALSE); + return g_hash_table_size(group->invalid_fields) == 0; --- a/libpurple/purplerequestgroup.h Thu Mar 16 22:36:19 2023 -0500
+++ b/libpurple/purplerequestgroup.h Thu Mar 16 22:50:08 2023 -0500
@@ -107,6 +107,18 @@
PurpleRequestPage *purple_request_group_get_page(PurpleRequestGroup *group);
+ * purple_request_group_is_valid: + * Returns whether or not all fields are valid. + * Returns: %TRUE if all fields in the group are valid, %FALSE otherwise. +gboolean purple_request_group_is_valid(PurpleRequestGroup *group); #endif /* PURPLE_REQUEST_GROUP_H */
--- a/libpurple/purplerequestpage.c Thu Mar 16 22:36:19 2023 -0500
+++ b/libpurple/purplerequestpage.c Thu Mar 16 22:50:08 2023 -0500
@@ -34,6 +34,7 @@
+ GHashTable *invalid_groups; @@ -42,6 +43,38 @@
+static GParamSpec *properties[N_PROPERTIES] = {NULL, }; +/****************************************************************************** + *****************************************************************************/ +purple_request_page_notify_group_cb(GObject *obj, + G_GNUC_UNUSED GParamSpec *pspec, + PurpleRequestPage *page = PURPLE_REQUEST_PAGE(data); + PurpleRequestGroup *group = PURPLE_REQUEST_GROUP(obj); + gboolean before, after; + before = purple_request_page_is_valid(page); + if(purple_request_group_is_valid(group)) { + g_hash_table_remove(page->invalid_groups, group); + g_hash_table_add(page->invalid_groups, group); + after = purple_request_page_is_valid(page); + g_object_notify_by_pspec(G_OBJECT(page), properties[PROP_VALID]); /******************************************************************************
* GListModel Implementation
*****************************************************************************/
@@ -85,10 +118,27 @@
purple_request_page_list_model_init))
+purple_request_page_get_property(GObject *obj, guint param_id, GValue *value, + PurpleRequestPage *page = PURPLE_REQUEST_PAGE(obj); + g_value_set_boolean(value, purple_request_page_is_valid(page)); + G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec); purple_request_page_finalize(GObject *obj) {
PurpleRequestPage *page = PURPLE_REQUEST_PAGE(obj);
g_list_free_full(page->groups, g_object_unref);
+ g_clear_pointer(&page->invalid_groups, g_hash_table_destroy); g_list_free(page->required_fields);
g_list_free(page->validated_fields);
g_hash_table_destroy(page->fields);
@@ -99,6 +149,7 @@
purple_request_page_init(PurpleRequestPage *page) {
page->fields = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
+ page->invalid_groups = g_hash_table_new(g_direct_hash, g_direct_equal); @@ -106,6 +157,22 @@
GObjectClass *obj_class = G_OBJECT_CLASS(klass);
obj_class->finalize = purple_request_page_finalize;
+ obj_class->get_property = purple_request_page_get_property; + * PurpleRequestPage:valid: + * Whether all fields in a page are valid. + properties[PROP_VALID] = g_param_spec_boolean( + "Whether all fields in a page are valid.", + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + g_object_class_install_properties(obj_class, N_PROPERTIES, properties); /******************************************************************************
@@ -177,6 +244,10 @@
_purple_request_group_set_page(group, page);
+ purple_request_page_notify_group_cb(G_OBJECT(group), NULL, page); + g_signal_connect(group, "notify::valid", + G_CALLBACK(purple_request_page_notify_group_cb), page); for (l = purple_request_group_get_fields(group);
@@ -248,19 +319,10 @@
-purple_request_page_all_valid(PurpleRequestPage *page) {
+purple_request_page_is_valid(PurpleRequestPage *page) { g_return_val_if_fail(PURPLE_IS_REQUEST_PAGE(page), FALSE);
- for(l = page->validated_fields; l != NULL; l = l->next) {
- PurpleRequestField *field = PURPLE_REQUEST_FIELD(l->data);
- if (!purple_request_field_is_valid(field, NULL))
+ return g_hash_table_size(page->invalid_groups) == 0; --- a/libpurple/purplerequestpage.h Thu Mar 16 22:36:19 2023 -0500
+++ b/libpurple/purplerequestpage.h Thu Mar 16 22:50:08 2023 -0500
@@ -122,16 +122,16 @@
gboolean purple_request_page_all_required_filled(PurpleRequestPage *page);
- * purple_request_page_all_valid:
+ * purple_request_page_is_valid: * @page: The fields page.
* Returns whether or not all fields are valid.
- * Returns: TRUE if all fields are valid, or FALSE.
+ * Returns: %TRUE if all fields in the page are valid, %FALSE otherwise. -gboolean purple_request_page_all_valid(PurpleRequestPage *page);
+gboolean purple_request_page_is_valid(PurpleRequestPage *page); * purple_request_page_get_field:
--- a/libpurple/tests/meson.build Thu Mar 16 22:36:19 2023 -0500
+++ b/libpurple/tests/meson.build Thu Mar 16 22:50:08 2023 -0500
@@ -27,6 +27,8 @@
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/tests/test_request_group.c Thu Mar 16 22:50:08 2023 -0500
@@ -0,0 +1,103 @@
+ * Purple - Internet Messaging Library + * Copyright (C) Pidgin Developers <devel@pidgin.im> + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <https://www.gnu.org/licenses/>. +/****************************************************************************** + *****************************************************************************/ +test_request_group_valid_changed_cb(G_GNUC_UNUSED GObject *obj, + G_GNUC_UNUSED GParamSpec *pspec, +test_request_group_valid(void) { + PurpleRequestGroup *group = NULL; + PurpleRequestField *field1 = NULL, *field2 = NULL, *field3 = NULL; + group = purple_request_group_new("test-group"); + g_signal_connect(group, "notify::valid", + G_CALLBACK(test_request_group_valid_changed_cb), &called); + /* Empty groups are always valid. */ + g_assert_true(purple_request_group_is_valid(group)); + /* An added valid field keeps the group valid. */ + field1 = purple_request_field_int_new("test-int", "Test int", 50, 0, 100); + purple_request_group_add_field(group, field1); + g_assert_true(purple_request_group_is_valid(group)); + g_assert_cmpint(called, ==, 0); + /* Making the field invalid makes the group invalid. */ + purple_request_field_int_set_value(PURPLE_REQUEST_FIELD_INT(field1), -42); + g_assert_false(purple_request_group_is_valid(group)); + g_assert_cmpint(called, ==, 1); + /* Adding an invalid field keeps the group invalid. */ + field2 = purple_request_field_int_new("invalid", "Invalid", -42, 0, 100); + purple_request_group_add_field(group, field2); + g_assert_false(purple_request_group_is_valid(group)); + g_assert_cmpint(called, ==, 0); + /* Adding a valid field to an already invalid group does not change it to + * valid accidentally. */ + field3 = purple_request_field_int_new("valid", "Valid", 42, 0, 100); + purple_request_group_add_field(group, field3); + g_assert_false(purple_request_group_is_valid(group)); + g_assert_cmpint(called, ==, 0); + /* Making one field valid while others are still invalid keeps the group + purple_request_field_int_set_value(PURPLE_REQUEST_FIELD_INT(field1), 42); + g_assert_false(purple_request_group_is_valid(group)); + g_assert_cmpint(called, ==, 0); + /* Making last invalid field valid makes the group valid again. */ + purple_request_field_int_set_value(PURPLE_REQUEST_FIELD_INT(field2), 42); + g_assert_true(purple_request_group_is_valid(group)); + g_assert_cmpint(called, ==, 1); +/****************************************************************************** + *****************************************************************************/ +main(gint argc, gchar *argv[]) { + g_test_init(&argc, &argv, NULL); + g_test_add_func("/request-group/valid", test_request_group_valid); --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/tests/test_request_page.c Thu Mar 16 22:50:08 2023 -0500
@@ -0,0 +1,194 @@
+ * Purple - Internet Messaging Library + * Copyright (C) Pidgin Developers <devel@pidgin.im> + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <https://www.gnu.org/licenses/>. +/****************************************************************************** + *****************************************************************************/ +test_request_page_string_validator(PurpleRequestField *field, char **errmsg, + G_GNUC_UNUSED gpointer data) + /* Validator for a string field that is valid if the value is "valid". */ + PurpleRequestFieldString *strfield = PURPLE_REQUEST_FIELD_STRING(field); + const char *value = NULL; + gboolean result = TRUE; + value = purple_request_field_string_get_value(strfield); + if(!purple_strequal(value, "valid")) { + *errmsg = g_strdup_printf("String value is not valid: %s", value); +static PurpleRequestGroup * +test_request_page_new_valid_group(const char *name) { + PurpleRequestGroup *group = NULL; + PurpleRequestField *field = NULL; + char *field_name = NULL; + group = purple_request_group_new(name); + /* Field is valid, making the group valid. */ + field_name = g_strdup_printf("%s-string", name); + field = purple_request_field_string_new(field_name, field_name, "valid", + purple_request_field_set_validator(field, + test_request_page_string_validator, + purple_request_group_add_field(group, field); +static PurpleRequestGroup * +test_request_page_new_invalid_group(const char *name) { + PurpleRequestGroup *group = NULL; + PurpleRequestField *field = NULL; + char *field_name = NULL; + group = purple_request_group_new(name); + /* Field is invalid, making the group invalid. */ + field_name = g_strdup_printf("%s-string", name); + field = purple_request_field_string_new(field_name, field_name, "invalid", + purple_request_field_set_validator(field, + test_request_page_string_validator, + purple_request_group_add_field(group, field); +test_request_page_make_group_valid(PurpleRequestGroup *group) { + GListModel *model = G_LIST_MODEL(group); + n_items = g_list_model_get_n_items(model); + for(guint index = 0; index < n_items; index++) { + PurpleRequestFieldString *field = g_list_model_get_item(model, index); + purple_request_field_string_set_value(field, "valid"); +test_request_page_make_group_invalid(PurpleRequestGroup *group) { + GListModel *model = G_LIST_MODEL(group); + n_items = g_list_model_get_n_items(model); + for(guint index = 0; index < n_items; index++) { + PurpleRequestFieldString *field = g_list_model_get_item(model, index); + purple_request_field_string_set_value(field, "invalid"); +/****************************************************************************** + *****************************************************************************/ +test_request_page_valid_changed_cb(G_GNUC_UNUSED GObject *obj, + G_GNUC_UNUSED GParamSpec *pspec, +test_request_page_valid(void) { + PurpleRequestPage *page = NULL; + PurpleRequestGroup *group1 = NULL, *group2 = NULL, *group3 = NULL; + page = purple_request_page_new(); + g_signal_connect(page, "notify::valid", + G_CALLBACK(test_request_page_valid_changed_cb), &called); + /* Empty pages are always valid. */ + g_assert_true(purple_request_page_is_valid(page)); + /* An added valid group keeps the page valid. */ + group1 = test_request_page_new_valid_group("group1"); + purple_request_page_add_group(page, group1); + g_assert_true(purple_request_page_is_valid(page)); + g_assert_cmpint(called, ==, 0); + /* Making the group invalid makes the page invalid. */ + test_request_page_make_group_invalid(group1); + g_assert_false(purple_request_page_is_valid(page)); + g_assert_cmpint(called, ==, 1); + /* Adding an invalid group keeps the page invalid. */ + group2 = test_request_page_new_invalid_group("group2"); + purple_request_page_add_group(page, group2); + g_assert_false(purple_request_page_is_valid(page)); + g_assert_cmpint(called, ==, 0); + /* Adding a valid group to an already invalid page does not change it to + * valid accidentally. */ + group3 = test_request_page_new_valid_group("group3"); + purple_request_page_add_group(page, group3); + g_assert_false(purple_request_page_is_valid(page)); + g_assert_cmpint(called, ==, 0); + /* Making one group valid while others are still invalid keeps the group + test_request_page_make_group_valid(group1); + g_assert_false(purple_request_page_is_valid(page)); + g_assert_cmpint(called, ==, 0); + /* Making last invalid group valid makes the page valid again. */ + test_request_page_make_group_valid(group2); + g_assert_true(purple_request_page_is_valid(page)); + g_assert_cmpint(called, ==, 1); +/****************************************************************************** + *****************************************************************************/ +main(gint argc, gchar *argv[]) { + g_test_init(&argc, &argv, NULL); + g_test_add_func("/request-page/valid", test_request_page_valid); --- a/pidgin/gtkrequest.c Thu Mar 16 22:36:19 2023 -0500
+++ b/pidgin/gtkrequest.c Thu Mar 16 22:50:08 2023 -0500
@@ -235,7 +235,7 @@
gtk_widget_set_sensitive(req_data->ok_button,
purple_request_page_all_required_filled(page) &&
- purple_request_page_all_valid(page));
+ purple_request_page_is_valid(page)); @@ -2208,7 +2208,7 @@
gtk_widget_set_sensitive(data->ok_button, FALSE);
- if(!purple_request_page_all_valid(page)) {
+ if(!purple_request_page_is_valid(page)) { gtk_widget_set_sensitive(data->ok_button, FALSE);