--- 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 @@ char *title; GList *fields; + GHashTable *invalid_fields; }; enum { PROP_0, PROP_TITLE, + PROP_VALID, N_PROPERTIES, }; static GParamSpec *properties[N_PROPERTIES] = {NULL, }; @@ -53,6 +55,31 @@ } /****************************************************************************** + * Callbacks + *****************************************************************************/ +static void +purple_request_group_notify_field_cb(GObject *obj, + G_GNUC_UNUSED GParamSpec *pspec, + gpointer data) +{ + 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); + } else { + g_hash_table_add(group->invalid_fields, field); + } + after = purple_request_group_is_valid(group); + + if(before != after) { + g_object_notify_by_pspec(G_OBJECT(group), properties[PROP_VALID]); + } +} + +/****************************************************************************** * GListModel Implementation *****************************************************************************/ static GType @@ -104,6 +131,9 @@ case PROP_TITLE: g_value_set_string(value, purple_request_group_get_title(group)); break; + case PROP_VALID: + g_value_set_boolean(value, purple_request_group_is_valid(group)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec); break; @@ -133,12 +163,14 @@ g_free(group->title); 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); } static void -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); } static void @@ -162,6 +194,19 @@ NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); + /** + * PurpleRequestGroup:valid: + * + * Whether all fields in a group are valid. + * + * Since: 3.0.0 + */ + properties[PROP_VALID] = g_param_spec_boolean( + "valid", "valid", + "Whether all fields in a group are valid.", + TRUE, + 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 @@ return group->page; } + +gboolean +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; +}